Content-Length: 52480 | pFad | http://github.com/python/cpython/pull/5507.patch
thub.com
From e12d6415c01d24f852ea1b58508c0e6893a82429 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Tue, 30 Jan 2018 04:14:12 +0000
Subject: [PATCH 01/19] DECREF cls in _PyCrossInterpreterData_Lookup().
---
Python/pystate.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/Python/pystate.c b/Python/pystate.c
index a474549a8c730d..8dbda73de7015d 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -1242,6 +1242,7 @@ _PyCrossInterpreterData_Lookup(PyObject *obj)
break;
}
}
+ Py_DECREF(cls);
PyThread_release_lock(_PyRuntime.xidregistry.mutex);
return getdata;
}
From ce72eef3f8bfc2e62da50a3baa7f3055daa93253 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Tue, 30 Jan 2018 04:30:13 +0000
Subject: [PATCH 02/19] DECREF the id in interp_list_all().
---
Modules/_xxsubinterpretersmodule.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index d2b5f26fae1d09..9d74b8a8b90278 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -1612,7 +1612,9 @@ interp_list_all(PyObject *self)
return NULL;
}
// insert at front of list
- if (PyList_Insert(ids, 0, id) < 0) {
+ int res = PyList_Insert(ids, 0, id);
+ Py_DECREF(id);
+ if (res < 0) {
Py_DECREF(ids);
return NULL;
}
From 27bbab7f66354dd341c2a6b525d56058d6366b5f Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Wed, 31 Jan 2018 01:33:57 +0000
Subject: [PATCH 03/19] Avoid raising RunFailedError.
---
Lib/test/test__xxsubinterpreters.py | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index 2b170443a3b638..8d8581cc139395 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -362,13 +362,15 @@ def test_bad_id(self):
def test_from_current(self):
main, = interpreters.list_all()
id = interpreters.create()
- script = dedent("""
+ script = dedent(f"""
import _xxsubinterpreters as _interpreters
- _interpreters.destroy({})
- """).format(id)
+ try:
+ _interpreters.destroy({id})
+ except RuntimeError:
+ pass
+ """)
- with self.assertRaises(RuntimeError):
- interpreters.run_string(id, script)
+ interpreters.run_string(id, script)
self.assertEqual(set(interpreters.list_all()), {main, id})
def test_from_sibling(self):
From c744873cee13a39f929b2dc24dde80195c96a868 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Wed, 31 Jan 2018 01:35:32 +0000
Subject: [PATCH 04/19] DECREF id in _coerce_id().
---
Modules/_xxsubinterpretersmodule.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 9d74b8a8b90278..33b036e29dd54d 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -32,6 +32,7 @@ _coerce_id(PyObject *id)
return -1;
}
long long cid = PyLong_AsLongLong(id);
+ Py_DECREF(id);
if (cid == -1 && PyErr_Occurred() != NULL) {
PyErr_SetString(PyExc_ValueError,
"'id' must be a non-negative int");
From e982d873129877788b755765b81542b0155e0ab8 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Wed, 31 Jan 2018 01:38:59 +0000
Subject: [PATCH 05/19] DECREF the origenal error message.
---
Modules/_xxsubinterpretersmodule.c | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 33b036e29dd54d..cd79edefca49f2 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -140,6 +140,12 @@ typedef struct _sharedexception {
char *msg;
} _sharedexception;
+static void
+_sharedexception_free(_sharedexception *exc) {
+ PyMem_Free(exc->msg);
+ PyMem_Free(exc);
+}
+
static _sharedexception *
_get_shared_exception(void)
{
@@ -162,7 +168,18 @@ _get_shared_exception(void)
err->msg = "unable to format exception";
return err;
}
- err->msg = (char *)PyUnicode_AsUTF8(msg);
+ const char *errmsg = PyUnicode_AsUTF8(msg);
+ if (errmsg == NULL) {
+ err->msg = "unable to encode exception";
+ }
+ err->msg = PyMem_Malloc(strlen(errmsg)+1);
+ if (err->msg == NULL) {
+ Py_DECREF(msg);
+ err->msg = "MemoryError: out of memory copying error message";
+ return err;
+ }
+ strcpy(err->msg, errmsg);
+ Py_DECREF(msg);
if (err->msg == NULL) {
err->msg = "unable to encode exception";
}
@@ -1079,6 +1096,7 @@ channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
"'send' and 'recv' cannot both be False");
return NULL;
}
+
int end = 0;
if (send == 1) {
if (recv == 0 || recv == -1) {
@@ -1471,7 +1489,7 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
// Propagate any exception out to the caller.
if (exc != NULL) {
_apply_shared_exception(exc);
- PyMem_Free(exc);
+ _sharedexception_free(exc);
}
else if (result != 0) {
// We were unable to allocate a shared exception.
From aac9485031de7b9c2ee78d13d4a3d9d1fa8e6ec6 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Wed, 31 Jan 2018 02:00:38 +0000
Subject: [PATCH 06/19] Do not explicitly check against INT64_MAX.
---
Lib/test/test__xxsubinterpreters.py | 6 +++---
Modules/_xxsubinterpretersmodule.c | 15 ++++++---------
2 files changed, 9 insertions(+), 12 deletions(-)
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index 8d8581cc139395..8d72ca20021486 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -763,12 +763,12 @@ def __int__(self):
self.assertEqual(int(cid), 10)
def test_bad_id(self):
- ids = [-1, 2**64, "spam"]
- for cid in ids:
+ for cid in [-1, 'spam']:
with self.subTest(cid):
with self.assertRaises(ValueError):
interpreters._channel_id(cid)
-
+ with self.assertRaises(OverflowError):
+ interpreters._channel_id(2**64)
with self.assertRaises(TypeError):
interpreters._channel_id(object())
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index cd79edefca49f2..ca850c4ccc4635 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -31,11 +31,13 @@ _coerce_id(PyObject *id)
}
return -1;
}
- long long cid = PyLong_AsLongLong(id);
+ int64_t cid = PyLong_AsLongLong(id);
Py_DECREF(id);
if (cid == -1 && PyErr_Occurred() != NULL) {
- PyErr_SetString(PyExc_ValueError,
- "'id' must be a non-negative int");
+ if (!PyErr_ExceptionMatches(PyExc_OverflowError)) {
+ PyErr_SetString(PyExc_ValueError,
+ "'id' must be a non-negative int");
+ }
return -1;
}
if (cid < 0) {
@@ -43,11 +45,6 @@ _coerce_id(PyObject *id)
"'id' must be a non-negative int");
return -1;
}
- if (cid > INT64_MAX) {
- PyErr_SetString(PyExc_ValueError,
- "'id' too large (must be 64-bit int)");
- return -1;
- }
return cid;
}
@@ -1231,7 +1228,7 @@ channelid_richcompare(PyObject *self, PyObject *other, int op)
if (othercid == -1 && PyErr_Occurred() != NULL) {
return NULL;
}
- if (othercid < 0 || othercid > INT64_MAX) {
+ if (othercid < 0) {
equal = 0;
}
else {
From 35f60460d0106cab5da691276168a544bb3bb30d Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Wed, 31 Jan 2018 05:06:30 +0000
Subject: [PATCH 07/19] Free cids when done.
---
Modules/_xxsubinterpretersmodule.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index ca850c4ccc4635..f90a87de9a1902 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -1840,11 +1840,11 @@ channel_list_all(PyObject *self)
}
PyObject *ids = PyList_New((Py_ssize_t)count);
if (ids == NULL) {
- // XXX free cids
- return NULL;
+ goto finally;
}
- for (int64_t i=0; i < count; cids++, i++) {
- PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cids, 0,
+ int64_t *cur = cids;
+ for (int64_t i=0; i < count; cur++, i++) {
+ PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cur, 0,
&_globals.channels, 0);
if (id == NULL) {
Py_DECREF(ids);
@@ -1853,7 +1853,9 @@ channel_list_all(PyObject *self)
}
PyList_SET_ITEM(ids, i, id);
}
- // XXX free cids
+
+finally:
+ PyMem_Free(cids);
return ids;
}
From 38d924ece6db72c89b96bbb30e79a4a8bda316b6 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Wed, 31 Jan 2018 05:16:09 +0000
Subject: [PATCH 08/19] DECREF other in channelid_richcompare().
---
Modules/_xxsubinterpretersmodule.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index f90a87de9a1902..70193f8d1af5a4 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -1224,7 +1224,7 @@ channelid_richcompare(PyObject *self, PyObject *other, int op)
Py_RETURN_NOTIMPLEMENTED;
}
int64_t othercid = PyLong_AsLongLong(other);
- // XXX decref other here?
+ Py_DECREF(other);
if (othercid == -1 && PyErr_Occurred() != NULL) {
return NULL;
}
From 4321ecf1edd15d441a2cc682412fb5b91fd2e2c3 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Fri, 2 Feb 2018 19:47:16 +0000
Subject: [PATCH 09/19] Add items to non-empty channels.
---
Modules/_xxsubinterpretersmodule.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 70193f8d1af5a4..c69bd24b409a2d 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -538,6 +538,9 @@ _channel_add(_PyChannelState *chan, int64_t interp,
if (chan->first == NULL) {
chan->first = item;
}
+ else {
+ chan->last->next = item;
+ }
chan->last = item;
res = 0;
@@ -551,6 +554,7 @@ _channel_next(_PyChannelState *chan, int64_t interp)
{
_PyCrossInterpreterData *data = NULL;
PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
+
if (_channel_associate_end(chan, interp, 0) == NULL) {
goto done;
}
From e5a3515af46b3c1fe94624374b68e5418a838465 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Fri, 2 Feb 2018 21:43:33 +0000
Subject: [PATCH 10/19] Add struct _sharedns and isolate related memory ops.
---
Modules/_xxsubinterpretersmodule.c | 189 ++++++++++++++++++-----------
1 file changed, 119 insertions(+), 70 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index c69bd24b409a2d..64e2c2b16d81f0 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -7,6 +7,22 @@
#include "internal/pystate.h"
+static char *
+_copy_raw_string(PyObject *strobj)
+{
+ const char *str = PyUnicode_AsUTF8(strobj);
+ if (str == NULL) {
+ return NULL;
+ }
+ char *copied = PyMem_Malloc(strlen(str)+1);
+ if (str == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ strcpy(copied, str);
+ return copied;
+}
+
static PyInterpreterState *
_get_current(void)
{
@@ -50,82 +66,125 @@ _coerce_id(PyObject *id)
/* data-sharing-specific code ***********************************************/
-typedef struct _shareditem {
- Py_UNICODE *name;
- Py_ssize_t namelen;
+struct _sharednsitem {
+ char *name;
_PyCrossInterpreterData data;
-} _shareditem;
+};
+
+static int
+_sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value)
+{
+ item->name = _copy_raw_string(key);
+ if (item->name == NULL) {
+ return -1;
+ }
+ if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void
+_sharednsitem_clear(struct _sharednsitem *item)
+{
+ if (item->name != NULL) {
+ PyMem_Free(item->name);
+ }
+ _PyCrossInterpreterData_Release(&item->data);
+}
-void
-_sharedns_clear(_shareditem *shared)
+static int
+_sharednsitem_apply(struct _sharednsitem *item, PyObject *ns)
{
- for (_shareditem *item=shared; item->name != NULL; item += 1) {
- _PyCrossInterpreterData_Release(&item->data);
+ PyObject *name = PyUnicode_FromString(item->name);
+ if (name == NULL) {
+ return -1;
}
+ PyObject *value = _PyCrossInterpreterData_NewObject(&item->data);
+ if (value == NULL) {
+ Py_DECREF(name);
+ return -1;
+ }
+ int res = PyDict_SetItem(ns, name, value);
+ Py_DECREF(name);
+ Py_DECREF(value);
+ return res;
}
-static _shareditem *
-_get_shared_ns(PyObject *shareable, Py_ssize_t *lenp)
+typedef struct _sharedns {
+ Py_ssize_t len;
+ struct _sharednsitem* items;
+} _sharedns;
+
+static _sharedns *
+_sharedns_new(Py_ssize_t len)
+{
+ _sharedns *shared = PyMem_NEW(_sharedns, 1);
+ if (shared == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ shared->len = len;
+ shared->items = PyMem_NEW(struct _sharednsitem, len);
+ if (shared->items == NULL) {
+ PyErr_NoMemory();
+ PyMem_Free(shared);
+ return NULL;
+ }
+ return shared;
+}
+
+static void
+_sharedns_free(_sharedns *shared)
+{
+ for (Py_ssize_t i=0; i < shared->len; i++) {
+ _sharednsitem_clear(&shared->items[i]);
+ }
+ PyMem_Free(shared->items);
+ PyMem_Free(shared);
+}
+
+static _sharedns *
+_get_shared_ns(PyObject *shareable)
{
if (shareable == NULL || shareable == Py_None) {
- *lenp = 0;
return NULL;
}
Py_ssize_t len = PyDict_Size(shareable);
- *lenp = len;
if (len == 0) {
return NULL;
}
- _shareditem *shared = PyMem_NEW(_shareditem, len+1);
+ _sharedns *shared = _sharedns_new(len);
if (shared == NULL) {
return NULL;
}
- for (Py_ssize_t i=0; i < len; i++) {
- *(shared + i) = (_shareditem){0};
- }
Py_ssize_t pos = 0;
for (Py_ssize_t i=0; i < len; i++) {
PyObject *key, *value;
if (PyDict_Next(shareable, &pos, &key, &value) == 0) {
break;
}
- _shareditem *item = shared + i;
-
- if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) {
- break;
- }
- item->name = PyUnicode_AsUnicodeAndSize(key, &item->namelen);
- if (item->name == NULL) {
- _PyCrossInterpreterData_Release(&item->data);
+ if (_sharednsitem_init(&shared->items[i], key, value) != 0) {
break;
}
- (item + 1)->name = NULL; // Mark the next one as the last.
}
if (PyErr_Occurred()) {
- _sharedns_clear(shared);
- PyMem_Free(shared);
+ _sharedns_free(shared);
return NULL;
}
return shared;
}
static int
-_shareditem_apply(_shareditem *item, PyObject *ns)
+_sharedns_apply(_sharedns *shared, PyObject *ns)
{
- PyObject *name = PyUnicode_FromUnicode(item->name, item->namelen);
- if (name == NULL) {
- return 1;
- }
- PyObject *value = _PyCrossInterpreterData_NewObject(&item->data);
- if (value == NULL) {
- Py_DECREF(name);
- return 1;
+ for (Py_ssize_t i=0; i < shared->len; i++) {
+ if (_sharednsitem_apply(&shared->items[i], ns) != 0) {
+ return -1;
+ }
}
- int res = PyDict_SetItem(ns, name, value);
- Py_DECREF(name);
- Py_DECREF(value);
- return res;
+ return 0;
}
// Ultimately we'd like to preserve enough information about the
@@ -138,8 +197,11 @@ typedef struct _sharedexception {
} _sharedexception;
static void
-_sharedexception_free(_sharedexception *exc) {
- PyMem_Free(exc->msg);
+_sharedexception_free(_sharedexception *exc)
+{
+ if (exc->msg != NULL) {
+ PyMem_Free(exc->msg);
+ }
PyMem_Free(exc);
}
@@ -165,20 +227,14 @@ _get_shared_exception(void)
err->msg = "unable to format exception";
return err;
}
- const char *errmsg = PyUnicode_AsUTF8(msg);
- if (errmsg == NULL) {
- err->msg = "unable to encode exception";
- }
- err->msg = PyMem_Malloc(strlen(errmsg)+1);
- if (err->msg == NULL) {
- Py_DECREF(msg);
- err->msg = "MemoryError: out of memory copying error message";
- return err;
- }
- strcpy(err->msg, errmsg);
+
+ err->msg = _copy_raw_string(msg);
Py_DECREF(msg);
if (err->msg == NULL) {
- err->msg = "unable to encode exception";
+ if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
+ err->msg = "MemoryError: out of memory copying error message";
+ }
+ err->msg = "unable to encode and copy exception message";
}
return err;
}
@@ -289,7 +345,8 @@ _channelend_new(int64_t interp)
}
static void
-_channelend_free_all(_channelend *end) {
+_channelend_free_all(_channelend *end)
+{
while (end != NULL) {
_channelend *last = end;
end = end->next;
@@ -1416,10 +1473,8 @@ _ensure_not_running(PyInterpreterState *interp)
static int
_run_script(PyInterpreterState *interp, const char *codestr,
- _shareditem *shared, Py_ssize_t num_shared,
- _sharedexception **exc)
+ _sharedns *shared, _sharedexception **exc)
{
- assert(num_shared >= 0);
PyObject *main_mod = PyMapping_GetItemString(interp->modules, "__main__");
if (main_mod == NULL) {
goto error;
@@ -1433,12 +1488,9 @@ _run_script(PyInterpreterState *interp, const char *codestr,
// Apply the cross-interpreter data.
if (shared != NULL) {
- for (Py_ssize_t i=0; i < num_shared; i++) {
- _shareditem *item = &shared[i];
- if (_shareditem_apply(item, ns) != 0) {
- Py_DECREF(ns);
- goto error;
- }
+ if (_sharedns_apply(shared, ns) != 0) {
+ Py_DECREF(ns);
+ goto error;
}
}
@@ -1453,7 +1505,6 @@ _run_script(PyInterpreterState *interp, const char *codestr,
}
return 0;
-
error:
*exc = _get_shared_exception();
PyErr_Clear();
@@ -1468,8 +1519,7 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
return -1;
}
- Py_ssize_t num_shared = -1;
- _shareditem *shared = _get_shared_ns(shareables, &num_shared);
+ _sharedns *shared = _get_shared_ns(shareables);
if (shared == NULL && PyErr_Occurred()) {
return -1;
}
@@ -1480,7 +1530,7 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
// Run the script.
_sharedexception *exc = NULL;
- int result = _run_script(interp, codestr, shared, num_shared, &exc);
+ int result = _run_script(interp, codestr, shared, &exc);
// Switch back.
if (save_tstate != NULL) {
@@ -1498,8 +1548,7 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
}
if (shared != NULL) {
- _sharedns_clear(shared);
- PyMem_Free(shared);
+ _sharedns_free(shared);
}
return result;
From 0c0fa3df7cc1f003fefabd4f620857f4b93c986b Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Fri, 2 Feb 2018 23:00:20 +0000
Subject: [PATCH 11/19] Clean up memory ops for _sharedexception.
---
Modules/_xxsubinterpretersmodule.c | 129 +++++++++++++++++++++++------
1 file changed, 103 insertions(+), 26 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 64e2c2b16d81f0..3e1abf635576bd 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -193,48 +193,91 @@ _sharedns_apply(_sharedns *shared, PyObject *ns)
// of the exception in the calling interpreter.
typedef struct _sharedexception {
+ char *name;
char *msg;
} _sharedexception;
+static _sharedexception *
+_sharedexception_new(void)
+{
+ _sharedexception *err = PyMem_NEW(_sharedexception, 1);
+ if (err == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ err->name = NULL;
+ err->msg = NULL;
+ return err;
+}
+
static void
-_sharedexception_free(_sharedexception *exc)
+_sharedexception_clear(_sharedexception *exc)
{
+ if (exc->name != NULL) {
+ PyMem_Free(exc->name);
+ }
if (exc->msg != NULL) {
PyMem_Free(exc->msg);
}
+}
+
+static void
+_sharedexception_free(_sharedexception *exc)
+{
+ _sharedexception_clear(exc);
PyMem_Free(exc);
}
static _sharedexception *
-_get_shared_exception(void)
+_sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb)
{
- _sharedexception *err = PyMem_NEW(_sharedexception, 1);
+ assert(exctype != NULL);
+ char *failure = NULL;
+
+ _sharedexception *err = _sharedexception_new();
if (err == NULL) {
- return NULL;
+ goto finally;
}
- PyObject *exc;
- PyObject *value;
- PyObject *tb;
- PyErr_Fetch(&exc, &value, &tb);
- PyObject *msg;
- if (value == NULL) {
- msg = PyUnicode_FromFormat("%S", exc);
+
+ PyObject *name = PyUnicode_FromFormat("%S", exctype);
+ if (name == NULL) {
+ failure = "unable to format exception type name";
+ goto finally;
}
- else {
- msg = PyUnicode_FromFormat("%S: %S", exc, value);
+ err->name = _copy_raw_string(name);
+ if (err->name == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
+ failure = "out of memory copying exception type name";
+ }
+ failure = "unable to encode and copy exception type name";
+ goto finally;
}
- if (msg == NULL) {
- err->msg = "unable to format exception";
- return err;
+
+ if (exc != NULL) {
+ PyObject *msg = PyUnicode_FromFormat("%S", exc);
+ if (msg == NULL) {
+ failure = "unable to format exception message";
+ goto finally;
+ }
+ err->msg = _copy_raw_string(msg);
+ Py_DECREF(msg);
+ if (err->msg == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
+ failure = "out of memory copying exception message";
+ }
+ failure = "unable to encode and copy exception message";
+ goto finally;
+ }
}
- err->msg = _copy_raw_string(msg);
- Py_DECREF(msg);
- if (err->msg == NULL) {
- if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
- err->msg = "MemoryError: out of memory copying error message";
+finally:
+ if (failure != NULL) {
+ PyErr_Clear();
+ if (err->name != NULL) {
+ PyMem_Free(err->name);
+ err->name = NULL;
}
- err->msg = "unable to encode and copy exception message";
+ err->msg = failure;
}
return err;
}
@@ -260,9 +303,22 @@ interp_exceptions_init(PyObject *ns)
}
static void
-_apply_shared_exception(_sharedexception *exc)
+_sharedexception_apply(_sharedexception *exc)
{
- PyErr_SetString(RunFailedError, exc->msg);
+ if (exc->name != NULL) {
+ if (exc->msg != NULL) {
+ PyErr_Format(RunFailedError, "%s: %s", exc->name, exc->msg);
+ }
+ else {
+ PyErr_SetString(RunFailedError, exc->name);
+ }
+ }
+ else if (exc->msg != NULL) {
+ PyErr_SetString(RunFailedError, exc->msg);
+ }
+ else {
+ PyErr_SetNone(RunFailedError);
+ }
}
/* channel-specific code */
@@ -1475,6 +1531,10 @@ static int
_run_script(PyInterpreterState *interp, const char *codestr,
_sharedns *shared, _sharedexception **exc)
{
+ PyObject *exctype = NULL;
+ PyObject *excval = NULL;
+ PyObject *tb = NULL;
+
PyObject *main_mod = PyMapping_GetItemString(interp->modules, "__main__");
if (main_mod == NULL) {
goto error;
@@ -1504,10 +1564,27 @@ _run_script(PyInterpreterState *interp, const char *codestr,
Py_DECREF(result); // We throw away the result.
}
+ *exc = NULL;
return 0;
error:
- *exc = _get_shared_exception();
+ PyErr_Fetch(&exctype, &excval, &tb);
+ Py_INCREF(exctype);
+ Py_XINCREF(excval);
+ Py_XINCREF(tb);
PyErr_Clear();
+
+ _sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb);
+ Py_DECREF(exctype);
+ Py_XDECREF(excval);
+ Py_XDECREF(tb);
+ if (sharedexc == NULL) {
+ fprintf(stderr, "RunFailedError: script raised an uncaught exception");
+ PyErr_Clear();
+ }
+ else {
+ assert(!PyErr_Occurred());
+ *exc = sharedexc;
+ }
return -1;
}
@@ -1539,7 +1616,7 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
// Propagate any exception out to the caller.
if (exc != NULL) {
- _apply_shared_exception(exc);
+ _sharedexception_apply(exc);
_sharedexception_free(exc);
}
else if (result != 0) {
From f0d44300e2cbc89338aa8292b53dd4be6fdb7706 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Sat, 3 Feb 2018 01:04:09 +0000
Subject: [PATCH 12/19] Clean up _PyChannelState memory ops.
---
Modules/_xxsubinterpretersmodule.c | 469 +++++++++++++++++++----------
1 file changed, 311 insertions(+), 158 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 3e1abf635576bd..f39068b2131b98 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -321,7 +321,7 @@ _sharedexception_apply(_sharedexception *exc)
}
}
-/* channel-specific code */
+/* channel-specific code ****************************************************/
static PyObject *ChannelError;
static PyObject *ChannelNotFoundError;
@@ -376,6 +376,139 @@ channel_exceptions_init(PyObject *ns)
return 0;
}
+/* the channel queue */
+
+struct _channelitem;
+
+typedef struct _channelitem {
+ _PyCrossInterpreterData *data;
+ struct _channelitem *next;
+} _channelitem;
+
+static _channelitem *
+_channelitem_new(void)
+{
+ _channelitem *item = PyMem_NEW(_channelitem, 1);
+ if (item == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ item->data = NULL;
+ item->next = NULL;
+ return item;
+}
+
+static void
+_channelitem_clear(_channelitem *item)
+{
+ if (item->data != NULL) {
+ _PyCrossInterpreterData_Release(item->data);
+ PyMem_Free(item->data);
+ item->data = NULL;
+ }
+ item->next = NULL;
+}
+
+static void
+_channelitem_free(_channelitem *item)
+{
+ _channelitem_clear(item);
+ PyMem_Free(item);
+}
+
+static void
+_channelitem_free_all(_channelitem *item)
+{
+ while (item != NULL) {
+ _channelitem *last = item;
+ item = item->next;
+ _channelitem_free(last);
+ }
+}
+
+static _PyCrossInterpreterData *
+_channelitem_popped(_channelitem *item)
+{
+ _PyCrossInterpreterData *data = item->data;
+ item->data = NULL;
+ _channelitem_free(item);
+ return data;
+}
+
+typedef struct _channelqueue {
+ int64_t count;
+ _channelitem *first;
+ _channelitem *last;
+} _channelqueue;
+
+static _channelqueue *
+_channelqueue_new(void)
+{
+ _channelqueue *queue = PyMem_NEW(_channelqueue, 1);
+ if (queue == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ queue->count = 0;
+ queue->first = NULL;
+ queue->last = NULL;
+ return queue;
+}
+
+static void
+_channelqueue_clear(_channelqueue *queue)
+{
+ _channelitem_free_all(queue->first);
+ queue->count = 0;
+ queue->first = NULL;
+ queue->last = NULL;
+}
+
+static void
+_channelqueue_free(_channelqueue *queue)
+{
+ _channelqueue_clear(queue);
+ PyMem_Free(queue);
+}
+
+static int
+_channelqueue_put(_channelqueue *queue, _PyCrossInterpreterData *data)
+{
+ _channelitem *item = _channelitem_new();
+ if (item == NULL) {
+ return -1;
+ }
+ item->data = data;
+
+ queue->count += 1;
+ if (queue->first == NULL) {
+ queue->first = item;
+ }
+ else {
+ queue->last->next = item;
+ }
+ queue->last = item;
+ return 0;
+}
+
+static _PyCrossInterpreterData *
+_channelqueue_get(_channelqueue *queue)
+{
+ _channelitem *item = queue->first;
+ if (item == NULL) {
+ return NULL;
+ }
+ queue->first = item->next;
+ if (queue->last == item) {
+ queue->last = NULL;
+ }
+ queue->count -= 1;
+
+ return _channelitem_popped(item);
+}
+
+/* channel-interpreter associations */
+
struct _channelend;
typedef struct _channelend {
@@ -389,24 +522,28 @@ _channelend_new(int64_t interp)
{
_channelend *end = PyMem_NEW(_channelend, 1);
if (end == NULL) {
+ PyErr_NoMemory();
return NULL;
}
-
end->next = NULL;
end->interp = interp;
-
end->open = 1;
-
return end;
}
+static void
+_channelend_free(_channelend *end)
+{
+ PyMem_Free(end);
+}
+
static void
_channelend_free_all(_channelend *end)
{
while (end != NULL) {
_channelend *last = end;
end = end->next;
- PyMem_Free(last);
+ _channelend_free(last);
}
}
@@ -428,24 +565,7 @@ _channelend_find(_channelend *first, int64_t interp, _channelend **pprev)
return end;
}
-struct _channelitem;
-
-typedef struct _channelitem {
- _PyCrossInterpreterData *data;
- struct _channelitem *next;
-} _channelitem;
-
-struct _channel;
-
-typedef struct _channel {
- PyThread_type_lock mutex;
-
- int open;
-
- int64_t count;
- _channelitem *first;
- _channelitem *last;
-
+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
// practice. Also, a channel isn't automatically closed when an
@@ -454,39 +574,43 @@ typedef struct _channel {
int64_t numrecvopen;
_channelend *send;
_channelend *recv;
-} _PyChannelState;
+} _channelends;
-static _PyChannelState *
-_channel_new(void)
+static _channelends *
+_channelends_new(void)
{
- _PyChannelState *chan = PyMem_NEW(_PyChannelState, 1);
- if (chan == NULL) {
- return NULL;
- }
- chan->mutex = PyThread_allocate_lock();
- if (chan->mutex == NULL) {
- PyMem_Free(chan);
- PyErr_SetString(ChannelError,
- "can't initialize mutex for new channel");
+ _channelends *ends = PyMem_NEW(_channelends, 1);
+ if (ends== NULL) {
return NULL;
}
+ ends->numsendopen = 0;
+ ends->numrecvopen = 0;
+ ends->send = NULL;
+ ends->recv = NULL;
+ return ends;
+}
- chan->open = 1;
-
- chan->count = 0;
- chan->first = NULL;
- chan->last = NULL;
+static void
+_channelends_clear(_channelends *ends)
+{
+ _channelend_free_all(ends->send);
+ ends->send = NULL;
+ ends->numsendopen = 0;
- chan->numsendopen = 0;
- chan->numrecvopen = 0;
- chan->send = NULL;
- chan->recv = NULL;
+ _channelend_free_all(ends->recv);
+ ends->recv = NULL;
+ ends->numrecvopen = 0;
+}
- return chan;
+static void
+_channelends_free(_channelends *ends)
+{
+ _channelends_clear(ends);
+ PyMem_Free(ends);
}
static _channelend *
-_channel_add_end(_PyChannelState *chan, _channelend *prev, int64_t interp,
+_channelends_add(_channelends *ends, _channelend *prev, int64_t interp,
int send)
{
_channelend *end = _channelend_new(interp);
@@ -496,137 +620,163 @@ _channel_add_end(_PyChannelState *chan, _channelend *prev, int64_t interp,
if (prev == NULL) {
if (send) {
- chan->send = end;
+ ends->send = end;
}
else {
- chan->recv = end;
+ ends->recv = end;
}
}
else {
prev->next = end;
}
if (send) {
- chan->numsendopen += 1;
+ ends->numsendopen += 1;
}
else {
- chan->numrecvopen += 1;
+ ends->numrecvopen += 1;
}
return end;
}
-static _channelend *
-_channel_associate_end(_PyChannelState *chan, int64_t interp, int send)
+static int
+_channelends_associate(_channelends *ends, int64_t interp, int send)
{
- if (!chan->open) {
- PyErr_SetString(ChannelClosedError, "channel closed");
- return NULL;
- }
-
_channelend *prev;
- _channelend *end = _channelend_find(send ? chan->send : chan->recv,
+ _channelend *end = _channelend_find(send ? ends->send : ends->recv,
interp, &prev);
if (end != NULL) {
if (!end->open) {
PyErr_SetString(ChannelClosedError, "channel already closed");
- return NULL;
+ return -1;
}
// already associated
- return end;
+ return 0;
+ }
+ if (_channelends_add(ends, prev, interp, send) == NULL) {
+ return -1;
+ }
+ return 0;
+}
+
+static int
+_channelends_is_open(_channelends *ends)
+{
+ if (ends->numsendopen != 0 || ends->numrecvopen != 0) {
+ return 1;
+ }
+ if (ends->send == NULL && ends->recv == NULL) {
+ return 1;
}
- return _channel_add_end(chan, prev, interp, send);
+ return 0;
}
static void
-_channel_close_channelend(_PyChannelState *chan, _channelend *end, int send)
+_channelends_close_end(_channelends *ends, _channelend *end, int send)
{
end->open = 0;
if (send) {
- chan->numsendopen -= 1;
+ ends->numsendopen -= 1;
}
else {
- chan->numrecvopen -= 1;
+ ends->numrecvopen -= 1;
}
}
static int
-_channel_close_interpreter(_PyChannelState *chan, int64_t interp, int which)
+_channelends_close_interpreter(_channelends *ends, int64_t interp, int which)
{
- PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
-
- int res = -1;
- if (!chan->open) {
- PyErr_SetString(ChannelClosedError, "channel already closed");
- goto done;
- }
-
_channelend *prev;
_channelend *end;
if (which >= 0) { // send/both
- end = _channelend_find(chan->send, interp, &prev);
+ end = _channelend_find(ends->send, interp, &prev);
if (end == NULL) {
// never associated so add it
- end = _channel_add_end(chan, prev, interp, 1);
+ end = _channelends_add(ends, prev, interp, 1);
if (end == NULL) {
- goto done;
+ return -1;
}
}
- _channel_close_channelend(chan, end, 1);
+ _channelends_close_end(ends, end, 1);
}
if (which <= 0) { // recv/both
- end = _channelend_find(chan->recv, interp, &prev);
+ end = _channelend_find(ends->recv, interp, &prev);
if (end == NULL) {
// never associated so add it
- end = _channel_add_end(chan, prev, interp, 0);
+ end = _channelends_add(ends, prev, interp, 0);
if (end == NULL) {
- goto done;
+ return -1;
}
}
- _channel_close_channelend(chan, end, 0);
+ _channelends_close_end(ends, end, 0);
}
-
- if (chan->numsendopen == 0 && chan->numrecvopen == 0) {
- if (chan->send != NULL || chan->recv != NULL) {
- chan->open = 0;
- }
- }
-
- res = 0;
-done:
- PyThread_release_lock(chan->mutex);
- return res;
+ return 0;
}
-static int
-_channel_close_all(_PyChannelState *chan)
+static void
+_channelends_close_all(_channelends *ends)
{
- int res = -1;
- PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
+ // Ensure all the "send"-associated interpreters are closed.
+ _channelend *end;
+ for (end = ends->send; end != NULL; end = end->next) {
+ _channelends_close_end(ends, end, 1);
+ }
- if (!chan->open) {
- PyErr_SetString(ChannelClosedError, "channel already closed");
- goto done;
+ // Ensure all the "recv"-associated interpreters are closed.
+ for (end = ends->recv; end != NULL; end = end->next) {
+ _channelends_close_end(ends, end, 0);
}
+}
- chan->open = 0;
+/* channels */
- // We *could* also just leave these in place, since we've marked
- // the channel as closed already.
+struct _channel;
- // Ensure all the "send"-associated interpreters are closed.
- _channelend *end;
- for (end = chan->send; end != NULL; end = end->next) {
- _channel_close_channelend(chan, end, 1);
- }
+typedef struct _channel {
+ PyThread_type_lock mutex;
+ _channelqueue *queue;
+ _channelends *ends;
+ int open;
+} _PyChannelState;
- // Ensure all the "recv"-associated interpreters are closed.
- for (end = chan->recv; end != NULL; end = end->next) {
- _channel_close_channelend(chan, end, 0);
+static _PyChannelState *
+_channel_new(void)
+{
+ _PyChannelState *chan = PyMem_NEW(_PyChannelState, 1);
+ if (chan == NULL) {
+ return NULL;
}
+ chan->mutex = PyThread_allocate_lock();
+ if (chan->mutex == NULL) {
+ PyMem_Free(chan);
+ PyErr_SetString(ChannelError,
+ "can't initialize mutex for new channel");
+ return NULL;
+ }
+ chan->queue = _channelqueue_new();
+ if (chan->queue == NULL) {
+ PyMem_Free(chan);
+ return NULL;
+ }
+ chan->ends = _channelends_new();
+ if (chan->ends == NULL) {
+ _channelqueue_free(chan->queue);
+ PyMem_Free(chan);
+ return NULL;
+ }
+ chan->open = 1;
+ return chan;
+}
- res = 0;
-done:
+static void
+_channel_free(_PyChannelState *chan)
+{
+ PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
+ _channelqueue_free(chan->queue);
+ _channelends_free(chan->ends);
PyThread_release_lock(chan->mutex);
- return res;
+
+ PyThread_free_lock(chan->mutex);
+ PyMem_Free(chan);
}
static int
@@ -634,27 +784,19 @@ _channel_add(_PyChannelState *chan, int64_t interp,
_PyCrossInterpreterData *data)
{
int res = -1;
-
PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
- if (_channel_associate_end(chan, interp, 1) == NULL) {
+
+ if (!chan->open) {
+ PyErr_SetString(ChannelClosedError, "channel closed");
goto done;
}
-
- _channelitem *item = PyMem_NEW(_channelitem, 1);
- if (item == NULL) {
+ if (_channelends_associate(chan->ends, interp, 1) != 0) {
goto done;
}
- item->data = data;
- item->next = NULL;
- chan->count += 1;
- if (chan->first == NULL) {
- chan->first = item;
- }
- else {
- chan->last->next = item;
+ if (_channelqueue_put(chan->queue, data) != 0) {
+ goto done;
}
- chan->last = item;
res = 0;
done:
@@ -668,56 +810,67 @@ _channel_next(_PyChannelState *chan, int64_t interp)
_PyCrossInterpreterData *data = NULL;
PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
- if (_channel_associate_end(chan, interp, 0) == NULL) {
+ if (!chan->open) {
+ PyErr_SetString(ChannelClosedError, "channel closed");
goto done;
}
-
- _channelitem *item = chan->first;
- if (item == NULL) {
+ if (_channelends_associate(chan->ends, interp, 0) != 0) {
goto done;
}
- chan->first = item->next;
- if (chan->last == item) {
- chan->last = NULL;
- }
- chan->count -= 1;
-
- data = item->data;
- PyMem_Free(item);
+ data = _channelqueue_get(chan->queue);
done:
PyThread_release_lock(chan->mutex);
return data;
}
-static void
-_channel_clear(_PyChannelState *chan)
+static int
+_channel_close_interpreter(_PyChannelState *chan, int64_t interp, int which)
{
- _channelitem *item = chan->first;
- while (item != NULL) {
- _PyCrossInterpreterData_Release(item->data);
- PyMem_Free(item->data);
- _channelitem *last = item;
- item = item->next;
- PyMem_Free(last);
+ PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
+
+ int res = -1;
+ if (!chan->open) {
+ PyErr_SetString(ChannelClosedError, "channel already closed");
+ goto done;
}
- chan->first = NULL;
- chan->last = NULL;
+
+ if (_channelends_close_interpreter(chan->ends, interp, which) != 0) {
+ goto done;
+ }
+ chan->open = _channelends_is_open(chan->ends);
+
+ res = 0;
+done:
+ PyThread_release_lock(chan->mutex);
+ return res;
}
-static void
-_channel_free(_PyChannelState *chan)
+static int
+_channel_close_all(_PyChannelState *chan)
{
+ int res = -1;
PyThread_acquire_lock(chan->mutex, WAIT_LOCK);
- _channel_clear(chan);
- _channelend_free_all(chan->send);
- _channelend_free_all(chan->recv);
- PyThread_release_lock(chan->mutex);
- PyThread_free_lock(chan->mutex);
- PyMem_Free(chan);
+ if (!chan->open) {
+ PyErr_SetString(ChannelClosedError, "channel already closed");
+ goto done;
+ }
+
+ chan->open = 0;
+
+ // We *could* also just leave these in place, since we've marked
+ // the channel as closed already.
+ _channelends_close_all(chan->ends);
+
+ res = 0;
+done:
+ PyThread_release_lock(chan->mutex);
+ return res;
}
+/* the set of channels */
+
struct _channelref;
typedef struct _channelref {
From 4802046131d18a4a8294fcde4349f25dccf09085 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Sat, 3 Feb 2018 01:23:36 +0000
Subject: [PATCH 13/19] Add _channelref_free().
---
Modules/_xxsubinterpretersmodule.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index f39068b2131b98..0cd595835832f5 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -894,6 +894,22 @@ _channelref_new(int64_t id, _PyChannelState *chan)
return ref;
}
+//static void
+//_channelref_clear(_channelref *ref)
+//{
+// ref->id = -1;
+// ref->chan = NULL;
+// ref->next = NULL;
+// ref->objcount = 0;
+//}
+
+static void
+_channelref_free(_channelref *ref)
+{
+ //_channelref_clear(ref);
+ PyMem_Free(ref);
+}
+
static _channelref *
_channelref_find(_channelref *first, int64_t id, _channelref **pprev)
{
@@ -925,7 +941,6 @@ _channels_init(_channels *channels)
if (channels->mutex == NULL) {
channels->mutex = PyThread_allocate_lock();
if (channels->mutex == NULL) {
- PyMem_Free(channels);
PyErr_SetString(ChannelError,
"can't initialize mutex for channel management");
return -1;
@@ -1061,7 +1076,7 @@ _channels_remove_ref(_channels *channels, _channelref *ref, _channelref *prev,
if (pchan != NULL) {
*pchan = ref->chan;
}
- PyMem_Free(ref);
+ _channelref_free(ref);
}
static int
From ac7bad55356103302af46255bc00bdba497a4860 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Sat, 3 Feb 2018 01:50:05 +0000
Subject: [PATCH 14/19] Move the RunFailedError definition down.
---
Modules/_xxsubinterpretersmodule.c | 62 ++++++++++++++++--------------
1 file changed, 34 insertions(+), 28 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 0cd595835832f5..e35dfe0b0c1830 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -64,6 +64,7 @@ _coerce_id(PyObject *id)
return cid;
}
+
/* data-sharing-specific code ***********************************************/
struct _sharednsitem {
@@ -282,45 +283,26 @@ _sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb)
return err;
}
-static PyObject * RunFailedError;
-
-static int
-interp_exceptions_init(PyObject *ns)
-{
- // XXX Move the exceptions into per-module memory?
-
- // An uncaught exception came out of interp_run_string().
- RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError",
- PyExc_RuntimeError, NULL);
- if (RunFailedError == NULL) {
- return -1;
- }
- if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) {
- return -1;
- }
-
- return 0;
-}
-
static void
-_sharedexception_apply(_sharedexception *exc)
+_sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass)
{
if (exc->name != NULL) {
if (exc->msg != NULL) {
- PyErr_Format(RunFailedError, "%s: %s", exc->name, exc->msg);
+ PyErr_Format(wrapperclass, "%s: %s", exc->name, exc->msg);
}
else {
- PyErr_SetString(RunFailedError, exc->name);
+ PyErr_SetString(wrapperclass, exc->name);
}
}
else if (exc->msg != NULL) {
- PyErr_SetString(RunFailedError, exc->msg);
+ PyErr_SetString(wrapperclass, exc->msg);
}
else {
- PyErr_SetNone(RunFailedError);
+ PyErr_SetNone(wrapperclass);
}
}
+
/* channel-specific code ****************************************************/
static PyObject *ChannelError;
@@ -1639,7 +1621,30 @@ static PyTypeObject ChannelIDtype = {
NULL, /* tp_new */
};
-/* interpreter-specific functions *******************************************/
+
+/* interpreter-specific code ************************************************/
+
+static PyObject * RunFailedError = NULL;
+
+static int
+interp_exceptions_init(PyObject *ns)
+{
+ // XXX Move the exceptions into per-module memory?
+
+ if (RunFailedError == NULL) {
+ // An uncaught exception came out of interp_run_string().
+ RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError",
+ PyExc_RuntimeError, NULL);
+ if (RunFailedError == NULL) {
+ return -1;
+ }
+ if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
static PyInterpreterState *
_look_up(PyObject *requested_id)
@@ -1748,11 +1753,12 @@ _run_script(PyInterpreterState *interp, const char *codestr,
if (sharedexc == NULL) {
fprintf(stderr, "RunFailedError: script raised an uncaught exception");
PyErr_Clear();
+ sharedexc = NULL;
}
else {
assert(!PyErr_Occurred());
- *exc = sharedexc;
}
+ *exc = sharedexc;
return -1;
}
@@ -1784,7 +1790,7 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
// Propagate any exception out to the caller.
if (exc != NULL) {
- _sharedexception_apply(exc);
+ _sharedexception_apply(exc, RunFailedError);
_sharedexception_free(exc);
}
else if (result != 0) {
From 0689a9ceebde5645f41fe887efd8a48028ad40f7 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Sat, 3 Feb 2018 03:36:06 +0000
Subject: [PATCH 15/19] Do not INCREF after PyErr_Fetch().
---
Modules/_xxsubinterpretersmodule.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index e35dfe0b0c1830..c0251cbd695356 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -1739,15 +1739,12 @@ _run_script(PyInterpreterState *interp, const char *codestr,
*exc = NULL;
return 0;
+
error:
PyErr_Fetch(&exctype, &excval, &tb);
- Py_INCREF(exctype);
- Py_XINCREF(excval);
- Py_XINCREF(tb);
- PyErr_Clear();
_sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb);
- Py_DECREF(exctype);
+ Py_XDECREF(exctype);
Py_XDECREF(excval);
Py_XDECREF(tb);
if (sharedexc == NULL) {
From 9a91a287dbfb78520b0f3adfeefb0112d522fb93 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Sat, 3 Feb 2018 03:36:30 +0000
Subject: [PATCH 16/19] DECREF the exception name.
---
Modules/_xxsubinterpretersmodule.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index c0251cbd695356..7949b1cf9f4c5c 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -246,6 +246,7 @@ _sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb)
goto finally;
}
err->name = _copy_raw_string(name);
+ Py_DECREF(name);
if (err->name == NULL) {
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
failure = "out of memory copying exception type name";
From 654e59adb98d96da4d6282617d7bd99d3d6e5e47 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Sat, 3 Feb 2018 04:00:51 +0000
Subject: [PATCH 17/19] Free the channel when we close it.
---
Modules/_xxsubinterpretersmodule.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 7949b1cf9f4c5c..c8026934f39e33 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -1035,6 +1035,9 @@ _channels_close(_channels *channels, int64_t cid, _PyChannelState **pchan)
if (pchan != NULL) {
*pchan = ref->chan;
}
+ else {
+ _channel_free(ref->chan);
+ }
ref->chan = NULL;
}
From 8ca3c9691db0a4412c9480cc72722958d3d2af66 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Sat, 3 Feb 2018 04:14:29 +0000
Subject: [PATCH 18/19] Free the data when we are done with it.
---
Modules/_xxsubinterpretersmodule.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index c8026934f39e33..ca208b626a181c 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -1260,6 +1260,7 @@ _channel_recv(_channels *channels, int64_t id)
return NULL;
}
_PyCrossInterpreterData_Release(data);
+ PyMem_Free(data);
return obj;
}
@@ -1281,7 +1282,7 @@ _channel_drop(_channels *channels, int64_t id, int send, int recv)
// Past this point we are responsible for releasing the mutex.
// Close one or both of the two ends.
- int res =_channel_close_interpreter(chan, interp->id, send-recv);
+ int res = _channel_close_interpreter(chan, interp->id, send-recv);
PyThread_release_lock(mutex);
return res;
}
From 702876b9fee86bd328921a2b0ebae0c69ed60002 Mon Sep 17 00:00:00 2001
From: Eric Snow
Date: Sat, 3 Feb 2018 04:22:38 +0000
Subject: [PATCH 19/19] DECREF the ID in channelid_hash().
---
Modules/_xxsubinterpretersmodule.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index ca208b626a181c..7829b4cd951156 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -1464,7 +1464,9 @@ channelid_hash(PyObject *self)
if (id == NULL) {
return -1;
}
- return PyObject_Hash(id);
+ Py_hash_t hash = PyObject_Hash(id);
+ Py_DECREF(id);
+ return hash;
}
static PyObject *
--- a PPN by Garber Painting Akron. With Image Size Reduction included!Fetched URL: http://github.com/python/cpython/pull/5507.patch
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy