summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorGregory P. Smith <greg@krypto.org>2012-06-26 03:57:36 (GMT)
committerGregory P. Smith <greg@krypto.org>2012-06-26 03:57:36 (GMT)
commitb2ac4d693a5571336d397eff93445ca0ac0f4204 (patch)
treea03147b0f9867b72b0e7a6cad5b58d8ebab70075 /Objects
parented04f42b9916e89c65820eb236ab347323d983e0 (diff)
downloadcpython-b2ac4d693a5571336d397eff93445ca0ac0f4204.zip
cpython-b2ac4d693a5571336d397eff93445ca0ac0f4204.tar.gz
cpython-b2ac4d693a5571336d397eff93445ca0ac0f4204.tar.bz2
Fixes issue #12268 for file readline, readlines and read() and readinto methods.
They no longer lose data when an underlying read system call is interrupted. IOError is no longer raised due to a read system call returning EINTR from within these methods.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/fileobject.c65
1 files changed, 61 insertions, 4 deletions
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 1d8142e..561ec21 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -1080,12 +1080,23 @@ file_read(PyFileObject *f, PyObject *args)
return NULL;
bytesread = 0;
for (;;) {
+ int interrupted;
FILE_BEGIN_ALLOW_THREADS(f)
errno = 0;
chunksize = Py_UniversalNewlineFread(BUF(v) + bytesread,
buffersize - bytesread, f->f_fp, (PyObject *)f);
+ interrupted = ferror(f->f_fp) && errno == EINTR;
FILE_END_ALLOW_THREADS(f)
+ if (interrupted) {
+ clearerr(f->f_fp);
+ if (PyErr_CheckSignals()) {
+ Py_DECREF(v);
+ return NULL;
+ }
+ }
if (chunksize == 0) {
+ if (interrupted)
+ continue;
if (!ferror(f->f_fp))
break;
clearerr(f->f_fp);
@@ -1100,7 +1111,7 @@ file_read(PyFileObject *f, PyObject *args)
return NULL;
}
bytesread += chunksize;
- if (bytesread < buffersize) {
+ if (bytesread < buffersize && !interrupted) {
clearerr(f->f_fp);
break;
}
@@ -1141,12 +1152,23 @@ file_readinto(PyFileObject *f, PyObject *args)
ntodo = pbuf.len;
ndone = 0;
while (ntodo > 0) {
+ int interrupted;
FILE_BEGIN_ALLOW_THREADS(f)
errno = 0;
nnow = Py_UniversalNewlineFread(ptr+ndone, ntodo, f->f_fp,
(PyObject *)f);
+ interrupted = ferror(f->f_fp) && errno == EINTR;
FILE_END_ALLOW_THREADS(f)
+ if (interrupted) {
+ clearerr(f->f_fp);
+ if (PyErr_CheckSignals()) {
+ PyBuffer_Release(&pbuf);
+ return NULL;
+ }
+ }
if (nnow == 0) {
+ if (interrupted)
+ continue;
if (!ferror(f->f_fp))
break;
PyErr_SetFromErrno(PyExc_IOError);
@@ -1434,8 +1456,25 @@ get_line(PyFileObject *f, int n)
*buf++ = c;
if (c == '\n') break;
}
- if ( c == EOF && skipnextlf )
- newlinetypes |= NEWLINE_CR;
+ if (c == EOF) {
+ if (ferror(fp) && errno == EINTR) {
+ FUNLOCKFILE(fp);
+ FILE_ABORT_ALLOW_THREADS(f)
+ f->f_newlinetypes = newlinetypes;
+ f->f_skipnextlf = skipnextlf;
+
+ if (PyErr_CheckSignals()) {
+ Py_DECREF(v);
+ return NULL;
+ }
+ /* We executed Python signal handlers and got no exception.
+ * Now back to reading the line where we left off. */
+ clearerr(fp);
+ continue;
+ }
+ if (skipnextlf)
+ newlinetypes |= NEWLINE_CR;
+ }
} else /* If not universal newlines use the normal loop */
while ((c = GETC(fp)) != EOF &&
(*buf++ = c) != '\n' &&
@@ -1449,6 +1488,16 @@ get_line(PyFileObject *f, int n)
break;
if (c == EOF) {
if (ferror(fp)) {
+ if (errno == EINTR) {
+ if (PyErr_CheckSignals()) {
+ Py_DECREF(v);
+ return NULL;
+ }
+ /* We executed Python signal handlers and got no exception.
+ * Now back to reading the line where we left off. */
+ clearerr(fp);
+ continue;
+ }
PyErr_SetFromErrno(PyExc_IOError);
clearerr(fp);
Py_DECREF(v);
@@ -1624,7 +1673,7 @@ file_readlines(PyFileObject *f, PyObject *args)
size_t totalread = 0;
char *p, *q, *end;
int err;
- int shortread = 0;
+ int shortread = 0; /* bool, did the previous read come up short? */
if (f->f_fp == NULL)
return err_closed();
@@ -1654,6 +1703,14 @@ file_readlines(PyFileObject *f, PyObject *args)
sizehint = 0;
if (!ferror(f->f_fp))
break;
+ if (errno == EINTR) {
+ if (PyErr_CheckSignals()) {
+ goto error;
+ }
+ clearerr(f->f_fp);
+ shortread = 0;
+ continue;
+ }
PyErr_SetFromErrno(PyExc_IOError);
clearerr(f->f_fp);
goto error;