summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorGregory P. Smith <greg@krypto.org>2012-10-12 20:02:06 (GMT)
committerGregory P. Smith <greg@krypto.org>2012-10-12 20:02:06 (GMT)
commit99716166b15bd0a35f5d5a3b84b34b978cc28aef (patch)
tree0b7f8cecf5ad5a36c426f2c3d29edc495173c078 /Modules
parent2aa5afab4e9ebac2c390e44bf0ac8b1778a0a1bc (diff)
downloadcpython-99716166b15bd0a35f5d5a3b84b34b978cc28aef.zip
cpython-99716166b15bd0a35f5d5a3b84b34b978cc28aef.tar.gz
cpython-99716166b15bd0a35f5d5a3b84b34b978cc28aef.tar.bz2
Fixes Issue #12268 for the io module - File readline, readlines and
read or readall methods no longer lose data when an underlying read system call is interrupted within an io module object. IOError is no longer raised due to a read system call returning EINTR from within these methods. This is a backport of changeset 781b95159954 from 3.2. The earlier 2.7 changeset 67dc99a989cd already fixed this for the builtin python 2.x file object.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_io/_iomodule.h5
-rw-r--r--Modules/_io/bufferedio.c8
-rw-r--r--Modules/_io/fileio.c7
-rw-r--r--Modules/_io/iobase.c21
-rw-r--r--Modules/_io/textio.c16
5 files changed, 49 insertions, 8 deletions
diff --git a/Modules/_io/_iomodule.h b/Modules/_io/_iomodule.h
index 916ca49..c282e61 100644
--- a/Modules/_io/_iomodule.h
+++ b/Modules/_io/_iomodule.h
@@ -57,6 +57,11 @@ extern Py_ssize_t _PyIO_find_line_ending(
int translated, int universal, PyObject *readnl,
Py_UNICODE *start, Py_UNICODE *end, Py_ssize_t *consumed);
+/* 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.
+*/
+extern int _PyIO_trap_eintr(void);
#define DEFAULT_BUFFER_SIZE (8 * 1024) /* bytes */
diff --git a/Modules/_io/bufferedio.c b/Modules/_io/bufferedio.c
index dc5c9b5..019ec94 100644
--- a/Modules/_io/bufferedio.c
+++ b/Modules/_io/bufferedio.c
@@ -710,8 +710,8 @@ _buffered_init(buffered *self)
clears the error indicator), 0 otherwise.
Should only be called when PyErr_Occurred() is true.
*/
-static int
-_trap_eintr(void)
+int
+_PyIO_trap_eintr(void)
{
static PyObject *eintr_int = NULL;
PyObject *typ, *val, *tb;
@@ -1296,7 +1296,7 @@ _bufferedreader_raw_read(buffered *self, char *start, Py_ssize_t len)
*/
do {
res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readinto, memobj, NULL);
- } while (res == NULL && _trap_eintr());
+ } while (res == NULL && _PyIO_trap_eintr());
Py_DECREF(memobj);
if (res == NULL)
return -1;
@@ -1723,7 +1723,7 @@ _bufferedwriter_raw_write(buffered *self, char *start, Py_ssize_t len)
errno = 0;
res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_write, memobj, NULL);
errnum = errno;
- } while (res == NULL && _trap_eintr());
+ } while (res == NULL && _PyIO_trap_eintr());
Py_DECREF(memobj);
if (res == NULL)
return -1;
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
index a8567bf..5411665 100644
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -570,6 +570,13 @@ fileio_readall(fileio *self)
if (n == 0)
break;
if (n < 0) {
+ if (errno == EINTR) {
+ if (PyErr_CheckSignals()) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ continue;
+ }
if (total > 0)
break;
if (errno == EAGAIN) {
diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c
index caf85d5..04caea4 100644
--- a/Modules/_io/iobase.c
+++ b/Modules/_io/iobase.c
@@ -468,8 +468,14 @@ iobase_readline(PyObject *self, PyObject *args)
if (has_peek) {
PyObject *readahead = PyObject_CallMethod(self, "peek", "i", 1);
- if (readahead == NULL)
+ if (readahead == NULL) {
+ /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
+ when EINTR occurs so we needn't do it ourselves. */
+ if (_PyIO_trap_eintr()) {
+ continue;
+ }
goto fail;
+ }
if (!PyBytes_Check(readahead)) {
PyErr_Format(PyExc_IOError,
"peek() should have returned a bytes object, "
@@ -502,8 +508,14 @@ iobase_readline(PyObject *self, PyObject *args)
}
b = PyObject_CallMethod(self, "read", "n", nreadahead);
- if (b == NULL)
+ if (b == NULL) {
+ /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
+ when EINTR occurs so we needn't do it ourselves. */
+ if (_PyIO_trap_eintr()) {
+ continue;
+ }
goto fail;
+ }
if (!PyBytes_Check(b)) {
PyErr_Format(PyExc_IOError,
"read() should have returned a bytes object, "
@@ -811,6 +823,11 @@ rawiobase_readall(PyObject *self, PyObject *args)
PyObject *data = PyObject_CallMethod(self, "read",
"i", DEFAULT_BUFFER_SIZE);
if (!data) {
+ /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
+ when EINTR occurs so we needn't do it ourselves. */
+ if (_PyIO_trap_eintr()) {
+ continue;
+ }
Py_DECREF(chunks);
return NULL;
}
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c
index 1746604..e55c165 100644
--- a/Modules/_io/textio.c
+++ b/Modules/_io/textio.c
@@ -1518,8 +1518,14 @@ textiowrapper_read(textio *self, PyObject *args)
/* Keep reading chunks until we have n characters to return */
while (remaining > 0) {
res = textiowrapper_read_chunk(self);
- if (res < 0)
+ if (res < 0) {
+ /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
+ when EINTR occurs so we needn't do it ourselves. */
+ if (_PyIO_trap_eintr()) {
+ continue;
+ }
goto fail;
+ }
if (res == 0) /* EOF */
break;
if (chunks == NULL) {
@@ -1678,8 +1684,14 @@ _textiowrapper_readline(textio *self, Py_ssize_t limit)
while (!self->decoded_chars ||
!PyUnicode_GET_SIZE(self->decoded_chars)) {
res = textiowrapper_read_chunk(self);
- if (res < 0)
+ if (res < 0) {
+ /* NOTE: PyErr_SetFromErrno() calls PyErr_CheckSignals()
+ when EINTR occurs so we needn't do it ourselves. */
+ if (_PyIO_trap_eintr()) {
+ continue;
+ }
goto error;
+ }
if (res == 0)
break;
}