]> granicus.if.org Git - python/commitdiff
Fixes issue #12268: File readline, readlines and read() or readall() methods
authorGregory P. Smith <greg@krypto.org>
Sun, 24 Jun 2012 07:23:47 +0000 (00:23 -0700)
committerGregory P. Smith <greg@krypto.org>
Sun, 24 Jun 2012 07:23:47 +0000 (00:23 -0700)
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.

1  2 
Lib/test/test_io.py
Misc/NEWS
Modules/_io/_iomodule.h
Modules/_io/bufferedio.c
Modules/_io/fileio.c
Modules/_io/iobase.c
Modules/_io/textio.c

Simple merge
diff --cc Misc/NEWS
index 1b92b1631964ce4c84c7af3de92703ec4eb2f909,95f66d71eade140936c36d6dfae06d88a0c93de9..c429412788bd7cf3f5461336682feeed65ab7c84
+++ b/Misc/NEWS
@@@ -10,10 -10,11 +10,15 @@@ What's New in Python 3.3.0 Beta 1
  Core and Builtins
  -----------------
  
+ - Issue #12268: File readline, readlines and read() or readall() methods
+   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.
 +- Issue #11626: Add _SizeT functions to stable ABI.
 +
 +- Issue #15146: Add PyType_FromSpecWithBases. Patch by Robin Schreiber.
 +
  - Issue #15142: Fix reference leak when deallocating instances of types
    created using PyType_FromSpec().
  
index 987aac80e59b85023cc3aeff5add79df92f0a783,aa8bfd69ddf8718a231b173b6d817e2f11fd6b11..0fe90a3b3b2e0ce997744d34b8223e1fb1217409
@@@ -55,8 -55,13 +55,13 @@@ extern PyObject *_PyIncrementalNewlineD
     Otherwise, the function will scan further and return garbage. */
  extern Py_ssize_t _PyIO_find_line_ending(
      int translated, int universal, PyObject *readnl,
 -    Py_UNICODE *start, Py_UNICODE *end, Py_ssize_t *consumed);
 +    int kind, char *start, char *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 */
  
Simple merge
Simple merge
index b30bbb69a3a2f6eb0331087f7c7c7eb58d204bc0,2bba1bfd58fefd98026180e14c46ed63b376e1fe..dd052ae6e9d586a2bc35f20095def338a053a533
@@@ -474,11 -481,15 +474,15 @@@ iobase_readline(PyObject *self, PyObjec
          PyObject *b;
  
          if (has_peek) {
-             _Py_IDENTIFIER(peek);
 -            PyObject *readahead = PyObject_CallMethod(self, "peek", "i", 1);
 +            PyObject *readahead = _PyObject_CallMethodId(self, &PyId_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, "
              Py_DECREF(readahead);
          }
  
 -        b = PyObject_CallMethod(self, "read", "n", nreadahead);
 +        b = _PyObject_CallMethodId(self, &PyId_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, "
@@@ -823,10 -835,14 +833,15 @@@ rawiobase_readall(PyObject *self, PyObj
          return NULL;
  
      while (1) {
 -        PyObject *data = PyObject_CallMethod(self, "read",
 -                                             "i", DEFAULT_BUFFER_SIZE);
 +        _Py_IDENTIFIER(read);
 +        PyObject *data = _PyObject_CallMethodId(self, &PyId_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;
          }
index 287f165cb05cdf3cb37f2dafbb0b060dfc74dfc7,d86a1c7b6da6ee2c5379ce3c27ddfce1624ee5b4..d390d5a4267759ba933793d4e8cba2645da30dc5
@@@ -1559,9 -1540,15 +1559,15 @@@ textiowrapper_read(textio *self, PyObje
  
          /* Keep reading chunks until we have n characters to return */
          while (remaining > 0) {
 -            res = textiowrapper_read_chunk(self);
 +            res = textiowrapper_read_chunk(self, remaining);
-             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) {
@@@ -1726,10 -1705,16 +1732,16 @@@ _textiowrapper_readline(textio *self, P
          /* First, get some data if necessary */
          res = 1;
          while (!self->decoded_chars ||
 -               !PyUnicode_GET_SIZE(self->decoded_chars)) {
 -            res = textiowrapper_read_chunk(self);
 +               !PyUnicode_GET_LENGTH(self->decoded_chars)) {
 +            res = textiowrapper_read_chunk(self, 0);
-             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;
          }