Commit 99716166 authored by Gregory P. Smith's avatar Gregory P. Smith

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.
parent 2aa5afab
This diff is collapsed.
......@@ -414,6 +414,11 @@ Library
Extension Modules
-----------------
- Issue #12268: 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.
- Issue #16012: Fix a regression in pyexpat. The parser's UseForeignDTD()
method doesn't require an argument again.
......
......@@ -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 */
......
......@@ -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;
......
......@@ -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) {
......
......@@ -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;
}
......
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment