[pypy-commit] pypy py3k: Buffered IO should catch EINTR and retry.

amauryfa noreply at buildbot.pypy.org
Tue Nov 22 22:18:41 CET 2011


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3k
Changeset: r49673:32c718fe8261
Date: 2011-11-14 07:57 +0100
http://bitbucket.org/pypy/pypy/changeset/32c718fe8261/

Log:	Buffered IO should catch EINTR and retry.

diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py
--- a/pypy/module/_io/interp_bufferedio.py
+++ b/pypy/module/_io/interp_bufferedio.py
@@ -11,12 +11,23 @@
     W_IOBase, DEFAULT_BUFFER_SIZE, convert_size,
     check_readable_w, check_writable_w, check_seekable_w)
 from pypy.module._io.interp_io import W_BlockingIOError
+import errno
 
 STATE_ZERO, STATE_OK, STATE_DETACHED = range(3)
 
 class BlockingIOError(Exception):
     pass
 
+def trap_EINTR(space, e):
+    """Return True if an EnvironmentError with errno == EINTR is set."""
+    if not e.match(space, space.w_EnvironmentError):
+        return False
+    w_value = e.get_w_value(space)
+    w_errno = space.getattr(w_value, space.wrap("errno"))
+    if space.eq_w(w_errno, space.wrap(errno.EINTR)):
+        return True
+    return False
+
 class W_BufferedIOBase(W_IOBase):
     def _unsupportedoperation(self, space, message):
         w_exc = space.getattr(space.getbuiltinmodule('_io'),
@@ -315,7 +326,18 @@
 
     def _write(self, space, data):
         w_data = space.wrapbytes(data)
-        w_written = space.call_method(self.w_raw, "write", w_data)
+        # NOTE: wrap_oserror() calls 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).
+        while True:
+            try:
+                w_written = space.call_method(self.w_raw, "write", w_data)
+                break
+            except OperationError, e:
+                if trap_EINTR(space, e):
+                    continue
+                raise
         written = space.getindex_w(w_written, space.w_IOError)
         if not 0 <= written <= len(data):
             raise OperationError(space.w_IOError, space.wrap(
@@ -481,7 +503,18 @@
     def _raw_read(self, space, buffer, start, length):
         length = intmask(length)
         w_buf = space.wrap(RawBuffer(buffer, start, length))
-        w_size = space.call_method(self.w_raw, "readinto", w_buf)
+        # NOTE: wrap_oserror() calls 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).
+        while True:
+            try:
+                w_size = space.call_method(self.w_raw, "readinto", w_buf)
+                break
+            except OperationError, e:
+                if trap_EINTR(space, e):
+                    continue
+                raise
         if space.is_w(w_size, space.w_None):
             raise BlockingIOError()
         size = space.int_w(w_size)


More information about the pypy-commit mailing list