Content-Length: 74385 | pFad | http://github.com/python/cpython/pull/17323.patch
thub.com
From ec5aa60f9b025915510871c7bbbeb4ca56b885ae Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Tue, 12 Nov 2019 11:24:05 +0000
Subject: [PATCH 01/33] Attempt at implementing channel_list_interpreters()
---
Modules/_xxsubinterpretersmodule.c | 87 ++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 4a6ffdd3266783..19aca1ad70f7df 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -627,6 +627,30 @@ _channelends_associate(_channelends *ends, int64_t interp, int send)
return 0;
}
+static int64_t *
+_channelends_list_interpreters(_channelends *ends, int64_t *count, int send)
+{
+ int64_t *ids = NULL;
+ int64_t numopen = send ? ends->numsendopen : ends->numrecvopen;
+ if (numopen >= PY_SSIZE_T_MAX) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "too many interpreters using the channel");
+ goto done;
+ }
+ ids = PyMem_NEW(int64_t, (Py_ssize_t)numopen);
+ if (ids == NULL) {
+ goto done;
+ }
+ _channelend *ref = send ? ends->send : ends->recv;
+ for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
+ ids[i] = ref->interp;
+ }
+ *count = numopen;
+
+done:
+ return ids;
+}
+
static int
_channelends_is_open(_channelends *ends)
{
@@ -2323,6 +2347,67 @@ PyDoc_STRVAR(channel_list_all_doc,
\n\
Return the list of all IDs for active channels.");
+
+static PyObject *
+channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"cid", NULL};
+ int64_t cid;
+ _PyChannelState *chan;
+ int send = 1; /* Send or receive ends? */
+ int64_t count; /* Number of interpreters to return */
+ int64_t *ids; /* Array of interpreter IDs to return */
+ PyObject *id_obj;
+ PyObject *ret; /* Python list of interpreter IDs */
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:channel_list_interps",
+ kwlist, channel_id_converter, &cid)) {
+ return NULL;
+ }
+
+ chan = _channels_lookup(&_globals.channels, cid, NULL);
+ ids = _channelends_list_interpreters(chan->ends, &count, send);
+
+ ret = PyList_New((Py_ssize_t)count);
+ if (ret == NULL) {
+ goto finally;
+ }
+
+ for (int64_t i=0; i < count; i++) {
+ PyInterpreterState *interp = PyInterpreterState_Head();
+ while (interp != NULL) {
+ id_obj = _PyInterpreterState_GetIDObject(interp);
+ if (id_obj == NULL) {
+ goto except;
+ }
+ if (ids[i] == PyInterpreterState_GetID(interp)) {
+ int rc = PyList_SetItem(ret, i, id_obj);
+ Py_DECREF(id_obj);
+ if (rc < 0) {
+ goto except;
+ }
+ break;
+ }
+ interp = PyInterpreterState_Next(interp);
+ }
+ }
+
+except:
+ Py_XDECREF(ret);
+ ret = NULL;
+
+finally:
+ PyMem_Free(ids);
+ return ret;
+}
+
+PyDoc_STRVAR(channel_list_interpreters_doc,
+"channel_list_interpreters(cid) -> [id]\n\
+\n\
+Return the list of all interpreter IDs associated with the channel\n\
+XXX in the send direction.");
+
+
static PyObject *
channel_send(PyObject *self, PyObject *args, PyObject *kwds)
{
@@ -2476,6 +2561,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,
From ee781339735d021ae30feb8995523b5eb5bc8439 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Tue, 12 Nov 2019 16:56:12 +0000
Subject: [PATCH 02/33] Fix some error cases
---
Modules/_xxsubinterpretersmodule.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 19aca1ad70f7df..b265c7d87d2eaa 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2356,21 +2356,25 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
_PyChannelState *chan;
int send = 1; /* Send or receive ends? */
int64_t count; /* Number of interpreters to return */
- int64_t *ids; /* Array of interpreter IDs to return */
- PyObject *id_obj;
- PyObject *ret; /* Python list of interpreter IDs */
+ int64_t *ids = NULL; /* Array of interpreter IDs to return */
+ PyObject *id_obj = NULL;
+ PyObject *ret = NULL; /* Python list of interpreter IDs */
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:channel_list_interps",
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:channel_list_interpreters",
kwlist, channel_id_converter, &cid)) {
return NULL;
}
chan = _channels_lookup(&_globals.channels, cid, NULL);
+ if (chan == NULL) {
+ goto except;
+ }
+
ids = _channelends_list_interpreters(chan->ends, &count, send);
ret = PyList_New((Py_ssize_t)count);
if (ret == NULL) {
- goto finally;
+ goto except;
}
for (int64_t i=0; i < count; i++) {
@@ -2392,6 +2396,8 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
}
}
+ goto finally;
+
except:
Py_XDECREF(ret);
ret = NULL;
From 433a5b0aef9fdbf873d350a741a21fbf60f4f1ad Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Tue, 12 Nov 2019 17:46:43 +0000
Subject: [PATCH 03/33] Fix issue with decreasing list items' references
---
Modules/_xxsubinterpretersmodule.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index b265c7d87d2eaa..7eb67cec93baeb 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2382,14 +2382,11 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
while (interp != NULL) {
id_obj = _PyInterpreterState_GetIDObject(interp);
if (id_obj == NULL) {
+ Py_DECREF(id_obj);
goto except;
}
if (ids[i] == PyInterpreterState_GetID(interp)) {
- int rc = PyList_SetItem(ret, i, id_obj);
- Py_DECREF(id_obj);
- if (rc < 0) {
- goto except;
- }
+ PyList_SET_ITEM(ret, i, id_obj);
break;
}
interp = PyInterpreterState_Next(interp);
From 64c1661854ea7488abaa14adfd2125ccb71fff18 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Wed, 20 Nov 2019 11:32:45 +0000
Subject: [PATCH 04/33] Fix issue with reference to interpreter
---
Modules/_xxsubinterpretersmodule.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 7eb67cec93baeb..eb65e10479c368 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2388,6 +2388,8 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
if (ids[i] == PyInterpreterState_GetID(interp)) {
PyList_SET_ITEM(ret, i, id_obj);
break;
+ } else {
+ Py_DECREF(id_obj);
}
interp = PyInterpreterState_Next(interp);
}
From 2c5c6df01629e304cef490814a05938c57c73b83 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Wed, 20 Nov 2019 11:34:07 +0000
Subject: [PATCH 05/33] Add ability to list interpreters on send or receive
channels
---
Modules/_xxsubinterpretersmodule.c | 22 ++++++++++++++--------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index eb65e10479c368..c1d6f3f7d17394 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2354,17 +2354,23 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
static char *kwlist[] = {"cid", NULL};
int64_t cid;
_PyChannelState *chan;
- int send = 1; /* Send or receive ends? */
- int64_t count; /* Number of interpreters to return */
- int64_t *ids = NULL; /* Array of interpreter IDs to return */
- PyObject *id_obj = NULL;
+ int send = 0; /* Send end? */
+ int recv = 0; /* Receive end? */
+ int64_t *ids = NULL; /* Array of interpreter IDs */
+ int64_t count = 0; /* Number of interpreters to return */
PyObject *ret = NULL; /* Python list of interpreter IDs */
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:channel_list_interpreters",
- kwlist, channel_id_converter, &cid)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|$pp:channel_list_interpreters",
+ kwlist, channel_id_converter, &cid, &send, &recv)) {
return NULL;
}
+ if ((send && recv) || (!send && !recv)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Can only list interpreters for a single end of a channel");
+ goto except;
+ }
+
chan = _channels_lookup(&_globals.channels, cid, NULL);
if (chan == NULL) {
goto except;
@@ -2380,7 +2386,7 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
for (int64_t i=0; i < count; i++) {
PyInterpreterState *interp = PyInterpreterState_Head();
while (interp != NULL) {
- id_obj = _PyInterpreterState_GetIDObject(interp);
+ PyObject *id_obj = _PyInterpreterState_GetIDObject(interp);
if (id_obj == NULL) {
Py_DECREF(id_obj);
goto except;
@@ -2407,7 +2413,7 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
}
PyDoc_STRVAR(channel_list_interpreters_doc,
-"channel_list_interpreters(cid) -> [id]\n\
+"channel_list_interpreters(cid, *, send=False, recv=False) -> [id]\n\
\n\
Return the list of all interpreter IDs associated with the channel\n\
XXX in the send direction.");
From 7f439fa8743d580f722103a34096ddd3c4df353f Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Wed, 20 Nov 2019 11:45:41 +0000
Subject: [PATCH 06/33] Fix arg parsing in C code
---
Modules/_xxsubinterpretersmodule.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index c1d6f3f7d17394..b5c9af0bf93f92 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2351,7 +2351,7 @@ Return the list of all IDs for active channels.");
static PyObject *
channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"cid", NULL};
+ static char *kwlist[] = {"cid", "send", "recv", NULL};
int64_t cid;
_PyChannelState *chan;
int send = 0; /* Send end? */
From d86ae971377dcae1e0bfffabd165c54e8a620f43 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Wed, 20 Nov 2019 11:58:49 +0000
Subject: [PATCH 07/33] Minor changes
---
Modules/_xxsubinterpretersmodule.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index b5c9af0bf93f92..ca227b5760880e 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2360,14 +2360,15 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
int64_t count = 0; /* Number of interpreters to return */
PyObject *ret = NULL; /* Python list of interpreter IDs */
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|$pp:channel_list_interpreters",
- kwlist, channel_id_converter, &cid, &send, &recv)) {
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds, "O&|$pp:channel_list_interpreters",
+ kwlist, channel_id_converter, &cid, &send, &recv)) {
return NULL;
}
if ((send && recv) || (!send && !recv)) {
- PyErr_SetString(PyExc_RuntimeError,
- "Can only list interpreters for a single end of a channel");
+ PyErr_SetString(PyExc_ValueError,
+ "Specify exactly one of send or recv");
goto except;
}
From c529c8814085200494224fd4c0a9039e84d07cef Mon Sep 17 00:00:00 2001
From: Benjamin Edwards
Date: Thu, 21 Nov 2019 02:58:04 -0800
Subject: [PATCH 08/33] Add channel_list_interpreters() tests
---
Lib/test/test__xxsubinterpreters.py | 75 ++++++++++++++++++++++++++++-
1 file changed, 74 insertions(+), 1 deletion(-)
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index 207b5db5d8fb9b..e5494212d4eada 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -1202,6 +1202,58 @@ def test_ids_global(self):
cid2 = int(out.strip())
self.assertEqual(cid2, int(cid1) + 1)
+
+ def _assert_interpreters_returned_are(self, cid, send, recv):
+ ilist = set(interpreters.channel_list_interpreters(cid, send=True))
+ self.assertEqual(ilist, set(send))
+ ilist = set(interpreters.channel_list_interpreters(cid, recv=True))
+ self.assertEqual(ilist, set(recv))
+
+ def test_channel_list_interpreters_empty(self):
+ # Test for channel with no associated interpreters.
+ cid = interpreters.channel_create()
+ self._assert_interpreters_returned_are(cid, [], [])
+
+ def test_channel_list_interpreters_mainline(self):
+ interp0 = interpreters.get_main()
+ cid = interpreters.channel_create()
+ interpreters.channel_send(cid, "send")
+ # Test for a channel that has one end associated to an interpreter.
+ self._assert_interpreters_returned_are(
+ cid, [interp0], [])
+
+ interp1 = interpreters.create()
+ _run_output(interp1, dedent(f"""
+ import _interpreters
+ obj = _interpreters.channel_recv({cid})
+ """))
+ # Test for channel that has boths ends associated to an interpreter.
+ self._assert_interpreters_returned_are(
+ cid, [interp0], [interp1])
+
+ def test_channel_list_interpreters_multiple(self):
+ # Test for channel with both ends associated to many interpreters.
+ interp0 = interpreters.get_main()
+ interp1 = interpreters.create()
+ interp2 = interpreters.create()
+ interp3 = interpreters.create()
+ cid = interpreters.channel_create()
+
+ interpreters.channel_send(cid, "send")
+ _run_output(interp1, dedent(f"""
+ import _interpreters
+ obj = _interpreters.channel_send({cid}, "send")
+ """))
+ _run_output(interp2, dedent(f"""
+ import _interpreters
+ obj = _interpreters.channel_recv({cid})
+ """))
+ _run_output(interp3, dedent(f"""
+ import _interpreters
+ obj = _interpreters.channel_recv({cid})
+ """))
+ self._assert_interpreters_returned_are(
+ cid, [interp0, interp1], [interp3, interp2])
####################
@@ -1514,7 +1566,28 @@ def test_close_used_multiple_times_by_single_user(self):
interpreters.channel_send(cid, b'eggs')
with self.assertRaises(interpreters.ChannelClosedError):
interpreters.channel_recv(cid)
-
+
+ def test_channel_list_interpreters_invalid_channel(self):
+ cid = interpreters.channel_create()
+ # Test for invalid channel ID.
+ with self.assertRaises(interpreters.ChannelNotFoundError):
+ interpreters.channel_list_interpreters(1000, send=True)
+
+ interpreters.channel_close(cid)
+ # Test for a channel that has been closed.
+ with self.assertRaises(interpreters.ChannelClosedError):
+ interpreters.channel_list_interpreters(cid, send=True)
+
+ def test_channel_list_interpreters_invalid_args(self):
+ # Tests for invalid arguments passed to the API.
+ cid = interpreters.channel_create()
+
+ with self.assertRaises(ValueError):
+ interpreters.channel_list_interpreters(cid)
+
+ with self.assertRaises(ValueError):
+ interpreters.channel_list_interpreters(cid, send=True, recv=True)
+
class ChannelReleaseTests(TestBase):
From 168ebf36028ade4e7db6588982453905abb6c0d0 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Thu, 21 Nov 2019 11:58:49 +0000
Subject: [PATCH 09/33] Fix docstring
---
Modules/_xxsubinterpretersmodule.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index ca227b5760880e..0c28946c57ff98 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2417,7 +2417,8 @@ PyDoc_STRVAR(channel_list_interpreters_doc,
"channel_list_interpreters(cid, *, send=False, recv=False) -> [id]\n\
\n\
Return the list of all interpreter IDs associated with the channel\n\
-XXX in the send direction.");
+Exactly one of 'send' or 'recv' should be True, corresponding to the end of\n\
+the channel to list interpreters for.");
static PyObject *
From 2a7b508e5ba107dd0c77e55587e137bf0f9a1e22 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Thu, 21 Nov 2019 12:12:43 +0000
Subject: [PATCH 10/33] Improve naming in tests
---
Lib/test/test__xxsubinterpreters.py | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index e5494212d4eada..d346f21aae976a 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -1203,23 +1203,23 @@ def test_ids_global(self):
self.assertEqual(cid2, int(cid1) + 1)
- def _assert_interpreters_returned_are(self, cid, send, recv):
- ilist = set(interpreters.channel_list_interpreters(cid, send=True))
- self.assertEqual(ilist, set(send))
- ilist = set(interpreters.channel_list_interpreters(cid, recv=True))
- self.assertEqual(ilist, set(recv))
+ def _assert_interpreters_returned(self, cid, send, recv):
+ actual = set(interpreters.channel_list_interpreters(cid, send=True))
+ self.assertEqual(actual, set(send))
+ actual = set(interpreters.channel_list_interpreters(cid, recv=True))
+ self.assertEqual(actual, set(recv))
def test_channel_list_interpreters_empty(self):
# Test for channel with no associated interpreters.
cid = interpreters.channel_create()
- self._assert_interpreters_returned_are(cid, [], [])
+ self._assert_interpreters_returned(cid, [], [])
def test_channel_list_interpreters_mainline(self):
interp0 = interpreters.get_main()
cid = interpreters.channel_create()
interpreters.channel_send(cid, "send")
# Test for a channel that has one end associated to an interpreter.
- self._assert_interpreters_returned_are(
+ self._assert_interpreters_returned(
cid, [interp0], [])
interp1 = interpreters.create()
@@ -1228,7 +1228,7 @@ def test_channel_list_interpreters_mainline(self):
obj = _interpreters.channel_recv({cid})
"""))
# Test for channel that has boths ends associated to an interpreter.
- self._assert_interpreters_returned_are(
+ self._assert_interpreters_returned(
cid, [interp0], [interp1])
def test_channel_list_interpreters_multiple(self):
@@ -1252,7 +1252,7 @@ def test_channel_list_interpreters_multiple(self):
import _interpreters
obj = _interpreters.channel_recv({cid})
"""))
- self._assert_interpreters_returned_are(
+ self._assert_interpreters_returned(
cid, [interp0, interp1], [interp3, interp2])
####################
From 4d6ac6ed5362d0fbb61d355e5e2aefd67e5e6048 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Thu, 21 Nov 2019 13:36:30 +0000
Subject: [PATCH 11/33] Add macros for int64_t max etc
---
Include/pyport.h | 24 ++++++++++++++++++++++++
Modules/_xxsubinterpretersmodule.c | 11 ++++++++---
2 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/Include/pyport.h b/Include/pyport.h
index 64c73f012e7a71..14b3a2cd335615 100644
--- a/Include/pyport.h
+++ b/Include/pyport.h
@@ -72,10 +72,34 @@ Used in: Py_SAFE_DOWNCAST
#define PY_UINT32_T uint32_t
#define PY_UINT64_T uint64_t
+#ifdef HAVE_STDINT_H
+#include
+#define PY_UINT32_T_MIN UINT32_MIN
+#define PY_UINT32_T_MAX UINT32_MAX
+#define PY_UINT64_T_MIN UINT64_MIN
+#define PY_UINT64_T_MAX UINT64_MAX
+#else
+#define PY_UINT32_T_MIN 0
+#define PY_UINT32_T_MAX ((uint32_t)-1)
+#define PY_UINT64_T_MIN 0
+#define PY_UINT64_T_MAX ((uint64_t)-1)
+#endif
/* Signed variants of the above */
#define PY_INT32_T int32_t
#define PY_INT64_T int64_t
+#ifdef HAVE_STDINT_H
+#include
+#define PY_INT32_T_MIN INT32_MIN
+#define PY_INT32_T_MAX INT32_MAX
+#define PY_INT64_T_MIN INT64_MIN
+#define PY_INT64_T_MAX INT64_MAX
+#else
+#define PY_INT32_T_MAX ((int32_t)(((uint32_t)-1)>>1))
+#define PY_INT32_T_MIN (-PY_INT32_T_MAX-1)
+#define PY_INT64_T_MAX ((int64_t)(((uint64_t)-1)>>1))
+#define PY_INT64_T_MIN (-PY_INT64_T_MAX-1)
+#endif
/* If PYLONG_BITS_IN_DIGIT is not defined then we'll use 30-bit digits if all
the necessary integer types are available, and we're on a 64-bit platform
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 0c28946c57ff98..0333f41d2f8ed7 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -631,8 +631,13 @@ static int64_t *
_channelends_list_interpreters(_channelends *ends, int64_t *count, int send)
{
int64_t *ids = NULL;
- int64_t numopen = send ? ends->numsendopen : ends->numrecvopen;
- if (numopen >= PY_SSIZE_T_MAX) {
+ int64_t numopen;
+
+ assert(ends != NULL);
+ assert(count != NULL);
+ numopen = send ? ends->numsendopen : ends->numrecvopen;
+
+ if (numopen >= PY_INT64_T_MAX) {
PyErr_SetString(PyExc_RuntimeError,
"too many interpreters using the channel");
goto done;
@@ -1202,7 +1207,7 @@ _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) {
+ if (numopen >= PY_INT64_T_MAX) {
PyErr_SetString(PyExc_RuntimeError, "too many channels open");
goto done;
}
From a44c2d271d4f526da0b4fd8c2e9611b5a9bc3218 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Thu, 21 Nov 2019 14:03:56 +0000
Subject: [PATCH 12/33] Fix error handling
---
Modules/_xxsubinterpretersmodule.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 0333f41d2f8ed7..320f9149d380a4 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -644,6 +644,7 @@ _channelends_list_interpreters(_channelends *ends, int64_t *count, int send)
}
ids = PyMem_NEW(int64_t, (Py_ssize_t)numopen);
if (ids == NULL) {
+ PyErr_SetNone(PyExc_MemoryError);
goto done;
}
_channelend *ref = send ? ends->send : ends->recv;
@@ -2383,6 +2384,9 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
}
ids = _channelends_list_interpreters(chan->ends, &count, send);
+ if (ids == NULL) {
+ goto except;
+ }
ret = PyList_New((Py_ssize_t)count);
if (ret == NULL) {
From 215300b3161f9dcfaf331dfc5e49b0201770f35b Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Thu, 21 Nov 2019 14:37:16 +0000
Subject: [PATCH 13/33] Expose _PyInterpreterState_LookUpID
---
Include/cpython/pystate.h | 2 ++
Modules/_xxsubinterpretersmodule.c | 25 +++++++++++--------------
2 files changed, 13 insertions(+), 14 deletions(-)
diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h
index 6c8d2ae041ea54..9d647e957b5616 100644
--- a/Include/cpython/pystate.h
+++ b/Include/cpython/pystate.h
@@ -147,6 +147,8 @@ struct _ts {
The caller must hold the GIL.*/
PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_Get(void);
+PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpID(PY_INT64_T requested_id);
+
PyAPI_FUNC(int) _PyState_AddModule(PyObject*, struct PyModuleDef*);
PyAPI_FUNC(PyThreadState *) _PyThreadState_Prealloc(PyInterpreterState *);
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 320f9149d380a4..21005448a6fb23 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2394,20 +2394,17 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
}
for (int64_t i=0; i < count; i++) {
- PyInterpreterState *interp = PyInterpreterState_Head();
- while (interp != NULL) {
- PyObject *id_obj = _PyInterpreterState_GetIDObject(interp);
- if (id_obj == NULL) {
- Py_DECREF(id_obj);
- goto except;
- }
- if (ids[i] == PyInterpreterState_GetID(interp)) {
- PyList_SET_ITEM(ret, i, id_obj);
- break;
- } else {
- Py_DECREF(id_obj);
- }
- interp = PyInterpreterState_Next(interp);
+ PyInterpreterState *interp = _PyInterpreterState_LookUpID(ids[i]);
+ PyObject *id_obj = _PyInterpreterState_GetIDObject(interp);
+ if (id_obj == NULL) {
+ Py_DECREF(id_obj);
+ goto except;
+ }
+ if (ids[i] == PyInterpreterState_GetID(interp)) {
+ PyList_SET_ITEM(ret, i, id_obj);
+ break;
+ } else {
+ Py_DECREF(id_obj);
}
}
From 9b124db988f86ed8c34777bec7d7179ca76a51f6 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Thu, 21 Nov 2019 15:29:01 +0000
Subject: [PATCH 14/33] Fix bad git rebase (use _xxsubinterpreters module name)
---
Lib/test/test__xxsubinterpreters.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index d346f21aae976a..f57f565d60f7b1 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -1224,7 +1224,7 @@ def test_channel_list_interpreters_mainline(self):
interp1 = interpreters.create()
_run_output(interp1, dedent(f"""
- import _interpreters
+ import _xxsubinterpreters as _interpreters
obj = _interpreters.channel_recv({cid})
"""))
# Test for channel that has boths ends associated to an interpreter.
@@ -1241,15 +1241,15 @@ def test_channel_list_interpreters_multiple(self):
interpreters.channel_send(cid, "send")
_run_output(interp1, dedent(f"""
- import _interpreters
+ import _xxsubinterpreters as _interpreters
obj = _interpreters.channel_send({cid}, "send")
"""))
_run_output(interp2, dedent(f"""
- import _interpreters
+ import _xxsubinterpreters as _interpreters
obj = _interpreters.channel_recv({cid})
"""))
_run_output(interp3, dedent(f"""
- import _interpreters
+ import _xxsubinterpreters as _interpreters
obj = _interpreters.channel_recv({cid})
"""))
self._assert_interpreters_returned(
From 76621c714256bf2bfd4728a27a9b3335d95ee563 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Thu, 21 Nov 2019 15:36:05 +0000
Subject: [PATCH 15/33] Remove decref of NULL
---
Modules/_xxsubinterpretersmodule.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 21005448a6fb23..dc58621cca2460 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2397,7 +2397,6 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
PyInterpreterState *interp = _PyInterpreterState_LookUpID(ids[i]);
PyObject *id_obj = _PyInterpreterState_GetIDObject(interp);
if (id_obj == NULL) {
- Py_DECREF(id_obj);
goto except;
}
if (ids[i] == PyInterpreterState_GetID(interp)) {
From d4c51bfbd3b8599e36cce32c4abe7ba48ea2873f Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Thu, 21 Nov 2019 15:44:41 +0000
Subject: [PATCH 16/33] Fix leftover broken code from nested loop
---
Modules/_xxsubinterpretersmodule.c | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index dc58621cca2460..949b1ceb29f969 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2399,12 +2399,7 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
if (id_obj == NULL) {
goto except;
}
- if (ids[i] == PyInterpreterState_GetID(interp)) {
- PyList_SET_ITEM(ret, i, id_obj);
- break;
- } else {
- Py_DECREF(id_obj);
- }
+ PyList_SET_ITEM(ret, i, id_obj);
}
goto finally;
From f3c2b34bc718f642c86a6391f1d465031ccc601f Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Thu, 21 Nov 2019 18:15:39 +0000
Subject: [PATCH 17/33] Remove whitespace from tests
---
Lib/test/test__xxsubinterpreters.py | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index f57f565d60f7b1..de69d19970f1af 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -1202,18 +1202,18 @@ def test_ids_global(self):
cid2 = int(out.strip())
self.assertEqual(cid2, int(cid1) + 1)
-
+
def _assert_interpreters_returned(self, cid, send, recv):
actual = set(interpreters.channel_list_interpreters(cid, send=True))
self.assertEqual(actual, set(send))
actual = set(interpreters.channel_list_interpreters(cid, recv=True))
self.assertEqual(actual, set(recv))
-
+
def test_channel_list_interpreters_empty(self):
# Test for channel with no associated interpreters.
cid = interpreters.channel_create()
self._assert_interpreters_returned(cid, [], [])
-
+
def test_channel_list_interpreters_mainline(self):
interp0 = interpreters.get_main()
cid = interpreters.channel_create()
@@ -1221,7 +1221,7 @@ def test_channel_list_interpreters_mainline(self):
# Test for a channel that has one end associated to an interpreter.
self._assert_interpreters_returned(
cid, [interp0], [])
-
+
interp1 = interpreters.create()
_run_output(interp1, dedent(f"""
import _xxsubinterpreters as _interpreters
@@ -1230,7 +1230,7 @@ def test_channel_list_interpreters_mainline(self):
# Test for channel that has boths ends associated to an interpreter.
self._assert_interpreters_returned(
cid, [interp0], [interp1])
-
+
def test_channel_list_interpreters_multiple(self):
# Test for channel with both ends associated to many interpreters.
interp0 = interpreters.get_main()
@@ -1238,7 +1238,7 @@ def test_channel_list_interpreters_multiple(self):
interp2 = interpreters.create()
interp3 = interpreters.create()
cid = interpreters.channel_create()
-
+
interpreters.channel_send(cid, "send")
_run_output(interp1, dedent(f"""
import _xxsubinterpreters as _interpreters
@@ -1566,28 +1566,28 @@ def test_close_used_multiple_times_by_single_user(self):
interpreters.channel_send(cid, b'eggs')
with self.assertRaises(interpreters.ChannelClosedError):
interpreters.channel_recv(cid)
-
+
def test_channel_list_interpreters_invalid_channel(self):
- cid = interpreters.channel_create()
- # Test for invalid channel ID.
+ cid = interpreters.channel_create()
+ # Test for invalid channel ID.
with self.assertRaises(interpreters.ChannelNotFoundError):
interpreters.channel_list_interpreters(1000, send=True)
-
+
interpreters.channel_close(cid)
# Test for a channel that has been closed.
with self.assertRaises(interpreters.ChannelClosedError):
interpreters.channel_list_interpreters(cid, send=True)
-
+
def test_channel_list_interpreters_invalid_args(self):
# Tests for invalid arguments passed to the API.
cid = interpreters.channel_create()
-
+
with self.assertRaises(ValueError):
interpreters.channel_list_interpreters(cid)
-
+
with self.assertRaises(ValueError):
interpreters.channel_list_interpreters(cid, send=True, recv=True)
-
+
class ChannelReleaseTests(TestBase):
From af10d1f3bf9c6317d8eb0546f230867ad8495e24 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Thu, 21 Nov 2019 18:19:00 +0000
Subject: [PATCH 18/33] Add to Misc/ACKS
---
Misc/ACKS | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Misc/ACKS b/Misc/ACKS
index 13c6676bace1fb..399a6724cd4990 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -444,6 +444,7 @@ Rodolpho Eckhardt
Ulrich Eckhardt
David Edelsohn
John Edmonds
+Benjamin Edwards
Grant Edwards
Zvi Effron
John Ehresman
@@ -557,6 +558,7 @@ Lars Marius Garshol
Jake Garver
Dan Gass
Andrew Gaul
+Lewis Gaul
Matthieu Gautier
Stephen M. Gava
Xavier de Gaye
From ac09b6cdeb0969e231f6e481bd7751894a1b28fc Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Fri, 22 Nov 2019 14:09:16 +0000
Subject: [PATCH 19/33] Remove PY_INT64_T_MAX etc. and use stdint.h
---
Include/pyport.h | 24 ------------------------
Modules/_xxsubinterpretersmodule.c | 4 ++--
2 files changed, 2 insertions(+), 26 deletions(-)
diff --git a/Include/pyport.h b/Include/pyport.h
index 14b3a2cd335615..64c73f012e7a71 100644
--- a/Include/pyport.h
+++ b/Include/pyport.h
@@ -72,34 +72,10 @@ Used in: Py_SAFE_DOWNCAST
#define PY_UINT32_T uint32_t
#define PY_UINT64_T uint64_t
-#ifdef HAVE_STDINT_H
-#include
-#define PY_UINT32_T_MIN UINT32_MIN
-#define PY_UINT32_T_MAX UINT32_MAX
-#define PY_UINT64_T_MIN UINT64_MIN
-#define PY_UINT64_T_MAX UINT64_MAX
-#else
-#define PY_UINT32_T_MIN 0
-#define PY_UINT32_T_MAX ((uint32_t)-1)
-#define PY_UINT64_T_MIN 0
-#define PY_UINT64_T_MAX ((uint64_t)-1)
-#endif
/* Signed variants of the above */
#define PY_INT32_T int32_t
#define PY_INT64_T int64_t
-#ifdef HAVE_STDINT_H
-#include
-#define PY_INT32_T_MIN INT32_MIN
-#define PY_INT32_T_MAX INT32_MAX
-#define PY_INT64_T_MIN INT64_MIN
-#define PY_INT64_T_MAX INT64_MAX
-#else
-#define PY_INT32_T_MAX ((int32_t)(((uint32_t)-1)>>1))
-#define PY_INT32_T_MIN (-PY_INT32_T_MAX-1)
-#define PY_INT64_T_MAX ((int64_t)(((uint64_t)-1)>>1))
-#define PY_INT64_T_MIN (-PY_INT64_T_MAX-1)
-#endif
/* If PYLONG_BITS_IN_DIGIT is not defined then we'll use 30-bit digits if all
the necessary integer types are available, and we're on a 64-bit platform
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 949b1ceb29f969..9713d39742457b 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -637,7 +637,7 @@ _channelends_list_interpreters(_channelends *ends, int64_t *count, int send)
assert(count != NULL);
numopen = send ? ends->numsendopen : ends->numrecvopen;
- if (numopen >= PY_INT64_T_MAX) {
+ if (numopen >= INT64_MAX) {
PyErr_SetString(PyExc_RuntimeError,
"too many interpreters using the channel");
goto done;
@@ -1208,7 +1208,7 @@ _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_INT64_T_MAX) {
+ if (numopen >= INT64_MAX) {
PyErr_SetString(PyExc_RuntimeError, "too many channels open");
goto done;
}
From 8e698649558a862bbe423ca44db7983a32325ff4 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Fri, 22 Nov 2019 14:12:15 +0000
Subject: [PATCH 20/33] Remove whitespace
---
Modules/_xxsubinterpretersmodule.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 9713d39742457b..f2991c494123f8 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2387,7 +2387,7 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
if (ids == NULL) {
goto except;
}
-
+
ret = PyList_New((Py_ssize_t)count);
if (ret == NULL) {
goto except;
From 0546702c41a292565c3cca261945e8f11931ed5d Mon Sep 17 00:00:00 2001
From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com>
Date: Fri, 22 Nov 2019 14:34:48 +0000
Subject: [PATCH 21/33] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?=
=?UTF-8?q?lurb=5Fit.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst | 1 +
1 file changed, 1 insertion(+)
create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst b/Misc/NEWS.d/next/Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst
new file mode 100644
index 00000000000000..6b3a356c8cfcf5
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst
@@ -0,0 +1 @@
+Added the ability to list interpreters associated with channel ends, as required for PEP 554.
\ No newline at end of file
From ad511ef6cf1f0882448407f8639cc05796fe43b3 Mon Sep 17 00:00:00 2001
From: Lewis G
Date: Sat, 23 Nov 2019 22:18:53 +0000
Subject: [PATCH 22/33] Update news entry to remove mention of PEP 554
---
.../Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst b/Misc/NEWS.d/next/Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst
index 6b3a356c8cfcf5..07a7f5ec22aa10 100644
--- a/Misc/NEWS.d/next/Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-11-22-14-34-47.bpo-38880.evcCPa.rst
@@ -1 +1 @@
-Added the ability to list interpreters associated with channel ends, as required for PEP 554.
\ No newline at end of file
+Added the ability to list interpreters associated with channel ends in the internal subinterpreters module.
From a1b7c3a681146af342595d1ebfb81a69cebefbe0 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Sat, 23 Nov 2019 22:58:29 +0000
Subject: [PATCH 23/33] Remove unnecessary asserts
---
Modules/_xxsubinterpretersmodule.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index f2991c494123f8..eab5e53a52420f 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -633,8 +633,6 @@ _channelends_list_interpreters(_channelends *ends, int64_t *count, int send)
int64_t *ids = NULL;
int64_t numopen;
- assert(ends != NULL);
- assert(count != NULL);
numopen = send ? ends->numsendopen : ends->numrecvopen;
if (numopen >= INT64_MAX) {
From d9b3e277d406509527e31f308dc04692ec675584 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Sat, 23 Nov 2019 23:01:09 +0000
Subject: [PATCH 24/33] Use single 'send' argument in
channel_list_interpreters() API
---
Lib/test/test__xxsubinterpreters.py | 8 ++------
Modules/_xxsubinterpretersmodule.c | 24 +++++++++---------------
2 files changed, 11 insertions(+), 21 deletions(-)
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index de69d19970f1af..b4b4f7bc141155 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -1206,7 +1206,7 @@ def test_ids_global(self):
def _assert_interpreters_returned(self, cid, send, recv):
actual = set(interpreters.channel_list_interpreters(cid, send=True))
self.assertEqual(actual, set(send))
- actual = set(interpreters.channel_list_interpreters(cid, recv=True))
+ actual = set(interpreters.channel_list_interpreters(cid, send=False))
self.assertEqual(actual, set(recv))
def test_channel_list_interpreters_empty(self):
@@ -1581,13 +1581,9 @@ def test_channel_list_interpreters_invalid_channel(self):
def test_channel_list_interpreters_invalid_args(self):
# Tests for invalid arguments passed to the API.
cid = interpreters.channel_create()
-
- with self.assertRaises(ValueError):
+ with self.assertRaises(TypeError):
interpreters.channel_list_interpreters(cid)
- with self.assertRaises(ValueError):
- interpreters.channel_list_interpreters(cid, send=True, recv=True)
-
class ChannelReleaseTests(TestBase):
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index eab5e53a52420f..7b89113bda997e 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2355,27 +2355,20 @@ 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", "recv", NULL};
+ static char *kwlist[] = {"cid", "send", NULL};
int64_t cid;
_PyChannelState *chan;
- int send = 0; /* Send end? */
- int recv = 0; /* Receive end? */
+ int send = 0; /* Send or receive end? */
int64_t *ids = NULL; /* Array of interpreter IDs */
int64_t count = 0; /* Number of interpreters to return */
PyObject *ret = NULL; /* Python list of interpreter IDs */
if (!PyArg_ParseTupleAndKeywords(
- args, kwds, "O&|$pp:channel_list_interpreters",
- kwlist, channel_id_converter, &cid, &send, &recv)) {
+ args, kwds, "O&$p:channel_list_interpreters",
+ kwlist, channel_id_converter, &cid, &send)) {
return NULL;
}
- if ((send && recv) || (!send && !recv)) {
- PyErr_SetString(PyExc_ValueError,
- "Specify exactly one of send or recv");
- goto except;
- }
-
chan = _channels_lookup(&_globals.channels, cid, NULL);
if (chan == NULL) {
goto except;
@@ -2412,11 +2405,12 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
}
PyDoc_STRVAR(channel_list_interpreters_doc,
-"channel_list_interpreters(cid, *, send=False, recv=False) -> [id]\n\
+"channel_list_interpreters(cid, *, send) -> [id]\n\
+\n\
+Return the list of all interpreter IDs associated with an end of the channel.\n\
\n\
-Return the list of all interpreter IDs associated with the channel\n\
-Exactly one of 'send' or 'recv' should be True, corresponding to the end of\n\
-the channel to list interpreters for.");
+The 'send' argument should be a boolean indicating whether to use the send or\n\
+receive end.");
static PyObject *
From f4990b01a541a222a7d8d5dc32cd34240d16e9af Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Sat, 23 Nov 2019 23:07:21 +0000
Subject: [PATCH 25/33] Tidy up _channelends_list_interpreters() function
---
Modules/_xxsubinterpretersmodule.c | 19 ++++++-------------
1 file changed, 6 insertions(+), 13 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 7b89113bda997e..8d6a45fe5d13f3 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -630,28 +630,21 @@ _channelends_associate(_channelends *ends, int64_t interp, int send)
static int64_t *
_channelends_list_interpreters(_channelends *ends, int64_t *count, int send)
{
- int64_t *ids = NULL;
- int64_t numopen;
-
- numopen = send ? ends->numsendopen : ends->numrecvopen;
+ int64_t numopen = send ? ends->numsendopen : ends->numrecvopen;
- if (numopen >= INT64_MAX) {
- PyErr_SetString(PyExc_RuntimeError,
- "too many interpreters using the channel");
- goto done;
- }
- ids = PyMem_NEW(int64_t, (Py_ssize_t)numopen);
+ int64_t *ids = PyMem_NEW(int64_t, (Py_ssize_t)numopen);
if (ids == NULL) {
- PyErr_SetNone(PyExc_MemoryError);
- goto done;
+ PyErr_NoMemory();
+ return NULL;
}
+
_channelend *ref = send ? ends->send : ends->recv;
for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
ids[i] = ref->interp;
}
+
*count = numopen;
-done:
return ids;
}
From c7dbb04af0fafe3044039bfb73ea47d03ae84e6c Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Sat, 23 Nov 2019 23:30:05 +0000
Subject: [PATCH 26/33] Move variable declarations inline
---
Modules/_xxsubinterpretersmodule.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 8d6a45fe5d13f3..739fd49eb99c7e 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2349,12 +2349,9 @@ static PyObject *
channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"cid", "send", NULL};
- int64_t cid;
- _PyChannelState *chan;
+ int64_t cid; /* Channel ID */
int send = 0; /* Send or receive end? */
- int64_t *ids = NULL; /* Array of interpreter IDs */
- int64_t count = 0; /* Number of interpreters to return */
- PyObject *ret = NULL; /* Python list of interpreter IDs */
+ PyObject *ret = NULL;
if (!PyArg_ParseTupleAndKeywords(
args, kwds, "O&$p:channel_list_interpreters",
@@ -2362,12 +2359,13 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
return NULL;
}
- chan = _channels_lookup(&_globals.channels, cid, NULL);
+ _PyChannelState *chan = _channels_lookup(&_globals.channels, cid, NULL);
if (chan == NULL) {
- goto except;
+ return NULL;
}
- ids = _channelends_list_interpreters(chan->ends, &count, send);
+ int64_t count = 0; /* Number of interpreters */
+ int64_t *ids = _channelends_list_interpreters(chan->ends, &count, send);
if (ids == NULL) {
goto except;
}
From 6202ecd358124f46ed6fad68c778b1cf6dfd1b49 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Sat, 23 Nov 2019 23:40:24 +0000
Subject: [PATCH 27/33] Use _PyInterpreterID_New() instead of getting existing
objects
---
Include/cpython/pystate.h | 2 --
Modules/_xxsubinterpretersmodule.c | 3 +--
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h
index 9d647e957b5616..6c8d2ae041ea54 100644
--- a/Include/cpython/pystate.h
+++ b/Include/cpython/pystate.h
@@ -147,8 +147,6 @@ struct _ts {
The caller must hold the GIL.*/
PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_Get(void);
-PyAPI_FUNC(PyInterpreterState *) _PyInterpreterState_LookUpID(PY_INT64_T requested_id);
-
PyAPI_FUNC(int) _PyState_AddModule(PyObject*, struct PyModuleDef*);
PyAPI_FUNC(PyThreadState *) _PyThreadState_Prealloc(PyInterpreterState *);
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 739fd49eb99c7e..4457f07c64b1ae 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2376,8 +2376,7 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
}
for (int64_t i=0; i < count; i++) {
- PyInterpreterState *interp = _PyInterpreterState_LookUpID(ids[i]);
- PyObject *id_obj = _PyInterpreterState_GetIDObject(interp);
+ PyObject *id_obj = _PyInterpreterID_New(ids[i]);
if (id_obj == NULL) {
goto except;
}
From 357101fd1551eb367d7df201d0c1ad6e3a217269 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Sat, 14 Dec 2019 17:54:53 +0000
Subject: [PATCH 28/33] Markups - remove check for number of open channels and
improve test structure
---
Lib/test/test__xxsubinterpreters.py | 37 ++++++++++++++++-------------
Modules/_xxsubinterpretersmodule.c | 5 ----
2 files changed, 21 insertions(+), 21 deletions(-)
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index b4b4f7bc141155..2b27aafb3a81bf 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -1203,24 +1203,25 @@ def test_ids_global(self):
self.assertEqual(cid2, int(cid1) + 1)
- def _assert_interpreters_returned(self, cid, send, recv):
- actual = set(interpreters.channel_list_interpreters(cid, send=True))
- self.assertEqual(actual, set(send))
- actual = set(interpreters.channel_list_interpreters(cid, send=False))
- self.assertEqual(actual, set(recv))
-
- def test_channel_list_interpreters_empty(self):
+ def test_channel_list_interpreters_none(self):
+ """Test listing interpreters for a channel with no associations."""
# Test for channel with no associated interpreters.
cid = interpreters.channel_create()
- self._assert_interpreters_returned(cid, [], [])
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ self.assertEqual(send_interps, [])
+ self.assertEqual(recv_interps, [])
- def test_channel_list_interpreters_mainline(self):
+ def test_channel_list_interpreters_basic(self):
+ """Test basic listing channel interpreters."""
interp0 = interpreters.get_main()
cid = interpreters.channel_create()
interpreters.channel_send(cid, "send")
# Test for a channel that has one end associated to an interpreter.
- self._assert_interpreters_returned(
- cid, [interp0], [])
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ self.assertEqual(send_interps, [interp0])
+ self.assertEqual(recv_interps, [])
interp1 = interpreters.create()
_run_output(interp1, dedent(f"""
@@ -1228,11 +1229,13 @@ def test_channel_list_interpreters_mainline(self):
obj = _interpreters.channel_recv({cid})
"""))
# Test for channel that has boths ends associated to an interpreter.
- self._assert_interpreters_returned(
- cid, [interp0], [interp1])
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ self.assertEqual(send_interps, [interp0])
+ self.assertEqual(recv_interps, [interp1])
def test_channel_list_interpreters_multiple(self):
- # Test for channel with both ends associated to many interpreters.
+ """Test listing interpreters for a channel with many associations."""
interp0 = interpreters.get_main()
interp1 = interpreters.create()
interp2 = interpreters.create()
@@ -1252,8 +1255,10 @@ def test_channel_list_interpreters_multiple(self):
import _xxsubinterpreters as _interpreters
obj = _interpreters.channel_recv({cid})
"""))
- self._assert_interpreters_returned(
- cid, [interp0, interp1], [interp3, interp2])
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ self.assertEqual(set(send_interps), {interp0, interp1})
+ self.assertEqual(set(recv_interps), {interp2, interp3})
####################
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 4457f07c64b1ae..95602d8669f076 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -1198,11 +1198,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 >= INT64_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;
From faca1dfba7b1a596a052796fbfc79c6406f3d5f7 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Tue, 21 Jan 2020 22:26:23 +0000
Subject: [PATCH 29/33] Add more listing subinterpreter tests
---
Lib/test/test__xxsubinterpreters.py | 97 +++++++++++++++++++++++++++++
1 file changed, 97 insertions(+)
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index 2b27aafb3a81bf..3d7e97b0173551 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -1260,6 +1260,103 @@ def test_channel_list_interpreters_multiple(self):
self.assertEqual(set(send_interps), {interp0, interp1})
self.assertEqual(set(recv_interps), {interp2, interp3})
+ @unittest.skip("Failing due to handling of destroyed interpreters")
+ def test_channel_list_interpreters_destroyed(self):
+ """Test listing channel interpreters with a destroyed interpreter."""
+ interp0 = interpreters.get_main()
+ interp1 = interpreters.create()
+ cid = interpreters.channel_create()
+ interpreters.channel_send(cid, "send")
+ _run_output(interp1, dedent(f"""
+ import _xxsubinterpreters as _interpreters
+ obj = _interpreters.channel_recv({cid})
+ """))
+ # Should be one interpreter associated with each end.
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ self.assertEqual(send_interps, [interp0])
+ self.assertEqual(recv_interps, [interp1])
+
+ interpreters.destroy(interp1)
+ # Destroyed interpreter should not be listed.
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ self.assertEqual(send_interps, [interp0])
+ self.assertEqual(recv_interps, [])
+
+ def test_channel_list_interpreters_released(self):
+ """Test listing channel interpreters with a released channel."""
+ # Set up one channel with main interpreter on the send end and two
+ # subinterpreters on the receive end.
+ interp0 = interpreters.get_main()
+ interp1 = interpreters.create()
+ interp2 = interpreters.create()
+ cid = interpreters.channel_create()
+ interpreters.channel_send(cid, "data")
+ _run_output(interp1, dedent(f"""
+ import _xxsubinterpreters as _interpreters
+ obj = _interpreters.channel_recv({cid})
+ """))
+ interpreters.channel_send(cid, "data")
+ _run_output(interp2, dedent(f"""
+ import _xxsubinterpreters as _interpreters
+ obj = _interpreters.channel_recv({cid})
+ """))
+ # Check the setup.
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ self.assertEqual(len(send_interps), 1)
+ self.assertEqual(len(recv_interps), 2)
+
+ # Release the main interpreter from the send end.
+ interpreters.channel_release(cid, send=True)
+ # Send end should raise an error for the main interpreter.
+ with self.assertRaises(interpreters.ChannelClosedError):
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ self.assertEqual(len(recv_interps), 2)
+
+ # Release one of the subinterpreters from the receive end.
+ _run_output(interp2, dedent(f"""
+ import _xxsubinterpreters as _interpreters
+ obj = _interpreters.channel_release({cid})
+ """))
+ # Receive end should have the released interpreter removed.
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ self.assertEqual(len(send_interps), 1)
+ self.assertEqual(recv_interps, [interp1])
+
+ def test_channel_list_interpreters_closed(self):
+ """Test listing channel interpreters with a closed channel."""
+ interp0 = interpreters.get_main()
+ interp1 = interpreters.create()
+ cid = interpreters.channel_create()
+ # Should be no interpreters associated with either end.
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ self.assertEqual(len(send_interps), 0)
+ self.assertEqual(len(recv_interps), 0)
+
+ # Close the send end of the channel.
+ interpreters.channel_close(cid, send=True)
+ # Send end should raise an error.
+ with self.assertRaises(interpreters.ChannelClosedError):
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ self.assertEqual(len(recv_interps), 0)
+
+ # Close the receive end of the channel from a subinterpreter.
+ _run_output(interp3, dedent(f"""
+ import _xxsubinterpreters as _interpreters
+ obj = _interpreters.channel_close({cid})
+ """))
+ # Both ends should raise an error.
+ with self.assertRaises(interpreters.ChannelClosedError):
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ with self.assertRaises(interpreters.ChannelClosedError):
+ recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+
####################
def test_send_recv_main(self):
From 75e791f66e3c83f53084d0a0d0463b68d9d929f8 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Sat, 18 Apr 2020 21:37:47 +0100
Subject: [PATCH 30/33] Implementation rewrite upon Eric's suggestion. Just one
testcase now failing
---
Lib/test/test__xxsubinterpreters.py | 9 ++--
Modules/_xxsubinterpretersmodule.c | 84 ++++++++++++++---------------
2 files changed, 44 insertions(+), 49 deletions(-)
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index 3d7e97b0173551..77e9f05296601c 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -1260,7 +1260,6 @@ def test_channel_list_interpreters_multiple(self):
self.assertEqual(set(send_interps), {interp0, interp1})
self.assertEqual(set(recv_interps), {interp2, interp3})
- @unittest.skip("Failing due to handling of destroyed interpreters")
def test_channel_list_interpreters_destroyed(self):
"""Test listing channel interpreters with a destroyed interpreter."""
interp0 = interpreters.get_main()
@@ -1310,10 +1309,10 @@ def test_channel_list_interpreters_released(self):
# Release the main interpreter from the send end.
interpreters.channel_release(cid, send=True)
- # Send end should raise an error for the main interpreter.
- with self.assertRaises(interpreters.ChannelClosedError):
- send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ # Send end should have no associated interpreters.
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ self.assertEqual(len(send_interps), 0)
self.assertEqual(len(recv_interps), 2)
# Release one of the subinterpreters from the receive end.
@@ -1324,7 +1323,7 @@ def test_channel_list_interpreters_released(self):
# Receive end should have the released interpreter removed.
send_interps = interpreters.channel_list_interpreters(cid, send=True)
recv_interps = interpreters.channel_list_interpreters(cid, send=False)
- self.assertEqual(len(send_interps), 1)
+ self.assertEqual(len(send_interps), 0)
self.assertEqual(recv_interps, [interp1])
def test_channel_list_interpreters_closed(self):
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 95602d8669f076..6e8d8d2b502dc4 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -536,7 +536,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;
@@ -627,27 +627,6 @@ _channelends_associate(_channelends *ends, int64_t interp, int send)
return 0;
}
-static int64_t *
-_channelends_list_interpreters(_channelends *ends, int64_t *count, int send)
-{
- int64_t numopen = send ? ends->numsendopen : ends->numrecvopen;
-
- int64_t *ids = PyMem_NEW(int64_t, (Py_ssize_t)numopen);
- if (ids == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
-
- _channelend *ref = send ? ends->send : ends->recv;
- for (int64_t i=0; ref != NULL; ref = ref->next, i++) {
- ids[i] = ref->interp;
- }
-
- *count = numopen;
-
- return ids;
-}
-
static int
_channelends_is_open(_channelends *ends)
{
@@ -1409,6 +1388,21 @@ _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;
+ }
+
+ _channelend *end = _channelend_find(send ? chan->ends->send : chan->ends->recv,
+ interp, NULL);
+
+ return (end != NULL && end->open);
+}
+
/* ChannelID class */
static PyTypeObject ChannelIDtype;
@@ -2339,14 +2333,15 @@ PyDoc_STRVAR(channel_list_all_doc,
\n\
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? */
- PyObject *ret = NULL;
+ int64_t id;
+ PyObject *ids, *id_obj;
+ PyInterpreterState *interp;
if (!PyArg_ParseTupleAndKeywords(
args, kwds, "O&$p:channel_list_interpreters",
@@ -2354,39 +2349,40 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
return NULL;
}
- _PyChannelState *chan = _channels_lookup(&_globals.channels, cid, NULL);
- if (chan == NULL) {
- return NULL;
- }
-
- int64_t count = 0; /* Number of interpreters */
- int64_t *ids = _channelends_list_interpreters(chan->ends, &count, send);
+ ids = PyList_New(0);
if (ids == NULL) {
goto except;
}
- ret = PyList_New((Py_ssize_t)count);
- if (ret == NULL) {
- goto except;
- }
-
- for (int64_t i=0; i < count; i++) {
- PyObject *id_obj = _PyInterpreterID_New(ids[i]);
- if (id_obj == NULL) {
+ 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;
}
- PyList_SET_ITEM(ret, i, id_obj);
+ if (res) {
+ id_obj = _PyInterpreterState_GetIDObject(interp);
+ if (id_obj == NULL) {
+ goto except;
+ }
+ res = PyList_Insert(ids, 0, id_obj);
+ if (res < 0) {
+ goto except;
+ }
+ }
+ interp = PyInterpreterState_Next(interp);
}
goto finally;
except:
- Py_XDECREF(ret);
- ret = NULL;
+ Py_XDECREF(ids);
+ ids = NULL;
finally:
- PyMem_Free(ids);
- return ret;
+ return ids;
}
PyDoc_STRVAR(channel_list_interpreters_doc,
From 79f5d35a8fee381527fe44c790eb79673da40666 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Tue, 28 Apr 2020 22:24:14 +0100
Subject: [PATCH 31/33] Fix issue with ChannelClosedError not being raised when
'send' end of channel is closed
---
Lib/test/test__xxsubinterpreters.py | 22 +++++++++++++---------
Modules/_xxsubinterpretersmodule.c | 3 +++
2 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index 77e9f05296601c..633cff6e7e2ab2 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -1245,7 +1245,7 @@ def test_channel_list_interpreters_multiple(self):
interpreters.channel_send(cid, "send")
_run_output(interp1, dedent(f"""
import _xxsubinterpreters as _interpreters
- obj = _interpreters.channel_send({cid}, "send")
+ _interpreters.channel_send({cid}, "send")
"""))
_run_output(interp2, dedent(f"""
import _xxsubinterpreters as _interpreters
@@ -1318,7 +1318,7 @@ def test_channel_list_interpreters_released(self):
# Release one of the subinterpreters from the receive end.
_run_output(interp2, dedent(f"""
import _xxsubinterpreters as _interpreters
- obj = _interpreters.channel_release({cid})
+ _interpreters.channel_release({cid})
"""))
# Receive end should have the released interpreter removed.
send_interps = interpreters.channel_list_interpreters(cid, send=True)
@@ -1331,30 +1331,34 @@ def test_channel_list_interpreters_closed(self):
interp0 = interpreters.get_main()
interp1 = interpreters.create()
cid = interpreters.channel_create()
- # Should be no interpreters associated with either end.
+ # Put something in the channel so that it's not empty.
+ interpreters.channel_send(cid, "send")
+
+ # Check initial state.
send_interps = interpreters.channel_list_interpreters(cid, send=True)
recv_interps = interpreters.channel_list_interpreters(cid, send=False)
- self.assertEqual(len(send_interps), 0)
+ self.assertEqual(len(send_interps), 1)
self.assertEqual(len(recv_interps), 0)
# Close the send end of the channel.
interpreters.channel_close(cid, send=True)
# Send end should raise an error.
with self.assertRaises(interpreters.ChannelClosedError):
- send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ interpreters.channel_list_interpreters(cid, send=True)
+ # Receive end should not be closed (since channel is not empty).
recv_interps = interpreters.channel_list_interpreters(cid, send=False)
self.assertEqual(len(recv_interps), 0)
# Close the receive end of the channel from a subinterpreter.
- _run_output(interp3, dedent(f"""
+ _run_output(interp1, dedent(f"""
import _xxsubinterpreters as _interpreters
- obj = _interpreters.channel_close({cid})
+ _interpreters.channel_close({cid}, force=True)
"""))
# Both ends should raise an error.
with self.assertRaises(interpreters.ChannelClosedError):
- send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ interpreters.channel_list_interpreters(cid, send=True)
with self.assertRaises(interpreters.ChannelClosedError):
- recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ interpreters.channel_list_interpreters(cid, send=False)
####################
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 6e8d8d2b502dc4..d460eeca1b8dc5 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -1395,6 +1395,9 @@ _channel_is_associated(_channels *channels, int64_t cid, int64_t interp,
_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,
From 5481e82e070d2472affa0313e0aa87e4936178d1 Mon Sep 17 00:00:00 2001
From: Lewis Gaul
Date: Tue, 28 Apr 2020 22:28:47 +0100
Subject: [PATCH 32/33] Add testcase for listing associated interpreters with
basic closed channel
---
Lib/test/test__xxsubinterpreters.py | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index 633cff6e7e2ab2..a98a8496ab8626 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -1340,6 +1340,28 @@ def test_channel_list_interpreters_closed(self):
self.assertEqual(len(send_interps), 1)
self.assertEqual(len(recv_interps), 0)
+ # Force close the channel.
+ interpreters.channel_close(cid, force=True)
+ # Both ends should raise an error.
+ with self.assertRaises(interpreters.ChannelClosedError):
+ interpreters.channel_list_interpreters(cid, send=True)
+ with self.assertRaises(interpreters.ChannelClosedError):
+ interpreters.channel_list_interpreters(cid, send=False)
+
+ def test_channel_list_interpreters_closed_send_end(self):
+ """Test listing channel interpreters with a channel's send end closed."""
+ interp0 = interpreters.get_main()
+ interp1 = interpreters.create()
+ cid = interpreters.channel_create()
+ # Put something in the channel so that it's not empty.
+ interpreters.channel_send(cid, "send")
+
+ # Check initial state.
+ send_interps = interpreters.channel_list_interpreters(cid, send=True)
+ recv_interps = interpreters.channel_list_interpreters(cid, send=False)
+ self.assertEqual(len(send_interps), 1)
+ self.assertEqual(len(recv_interps), 0)
+
# Close the send end of the channel.
interpreters.channel_close(cid, send=True)
# Send end should raise an error.
From 79be8a0d8bdd1b2f99d3495e7fcbd078dc1bcb47 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Tue, 28 Apr 2020 17:15:59 -0600
Subject: [PATCH 33/33] Fix a refleak.
---
Modules/_xxsubinterpretersmodule.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index d460eeca1b8dc5..e9ed08206aa3e0 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2371,6 +2371,7 @@ channel_list_interpreters(PyObject *self, PyObject *args, PyObject *kwds)
goto except;
}
res = PyList_Insert(ids, 0, id_obj);
+ Py_DECREF(id_obj);
if (res < 0) {
goto except;
}
--- a PPN by Garber Painting Akron. With Image Size Reduction included!Fetched URL: http://github.com/python/cpython/pull/17323.patch
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy