summaryrefslogtreecommitdiffstats
path: root/Modules/_io
diff options
context:
space:
mode:
authorAntoine Pitrou <solipsis@pitrou.net>2011-02-25 21:35:47 (GMT)
committerAntoine Pitrou <solipsis@pitrou.net>2011-02-25 21:35:47 (GMT)
commit6439c00a6dc1a079f7af0d8a44852fa75ece52a6 (patch)
treecb0bd75db802878c9f6ba0524d84938bc2062113 /Modules/_io
parent5217d3f9ca3ee5357f9dd9c47cfba04a00596c4a (diff)
downloadcpython-6439c00a6dc1a079f7af0d8a44852fa75ece52a6.zip
cpython-6439c00a6dc1a079f7af0d8a44852fa75ece52a6.tar.gz
cpython-6439c00a6dc1a079f7af0d8a44852fa75ece52a6.tar.bz2
Merged revisions 88610 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/branches/py3k ........ r88610 | antoine.pitrou | 2011-02-25 22:24:11 +0100 (ven., 25 févr. 2011) | 4 lines Issue #10956: Buffered I/O classes retry reading or writing after a signal has arrived and the handler returned successfully. ........
Diffstat (limited to 'Modules/_io')
-rw-r--r--Modules/_io/bufferedio.c51
1 files changed, 49 insertions, 2 deletions
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index 18cf1ca..5816a93 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -683,6 +683,39 @@ _buffered_init(buffered *self)
return 0;
}
+/* Return 1 if an EnvironmentError with errno == EINTR is set (and then
+ clears the error indicator), 0 otherwise.
+ Should only be called when PyErr_Occurred() is true.
+*/
+static int
+_trap_eintr(void)
+{
+ static PyObject *eintr_int = NULL;
+ PyObject *typ, *val, *tb;
+ PyEnvironmentErrorObject *env_err;
+
+ if (eintr_int == NULL) {
+ eintr_int = PyLong_FromLong(EINTR);
+ assert(eintr_int != NULL);
+ }
+ if (!PyErr_ExceptionMatches(PyExc_EnvironmentError))
+ return 0;
+ PyErr_Fetch(&typ, &val, &tb);
+ PyErr_NormalizeException(&typ, &val, &tb);
+ env_err = (PyEnvironmentErrorObject *) val;
+ assert(env_err != NULL);
+ if (env_err->myerrno != NULL &&
+ PyObject_RichCompareBool(env_err->myerrno, eintr_int, Py_EQ) > 0) {
+ Py_DECREF(typ);
+ Py_DECREF(val);
+ Py_XDECREF(tb);
+ return 1;
+ }
+ /* This silences any error set by PyObject_RichCompareBool() */
+ PyErr_Restore(typ, val, tb);
+ return 0;
+}
+
/*
* Shared methods and wrappers
*/
@@ -1243,7 +1276,14 @@ _bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len)
memobj = PyMemoryView_FromBuffer(&buf);
if (memobj == NULL)
return -1;
- res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readinto, memobj, NULL);
+ /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() when EINTR
+ occurs so we needn't do it ourselves.
+ We then retry reading, ignoring the signal if no handler has
+ raised (see issue #10956).
+ */
+ do {
+ res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readinto, memobj, NULL);
+ } while (res == NULL && _trap_eintr());
Py_DECREF(memobj);
if (res == NULL)
return -1;
@@ -1650,7 +1690,14 @@ _bufferedwriter_raw_write(buffered *self, char *start, Py_ssize_t len)
memobj = PyMemoryView_FromBuffer(&buf);
if (memobj == NULL)
return -1;
- res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_write, memobj, NULL);
+ /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals() when EINTR
+ occurs so we needn't do it ourselves.
+ We then retry writing, ignoring the signal if no handler has
+ raised (see issue #10956).
+ */
+ do {
+ res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_write, memobj, NULL);
+ } while (res == NULL && _trap_eintr());
Py_DECREF(memobj);
if (res == NULL)
return -1;