[pypy-commit] pypy merge-2.7.2: Buffered IO retries read() and write() when the raw stream raises errno=EINTR.
amauryfa
noreply at buildbot.pypy.org
Sun Jan 22 23:33:04 CET 2012
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: merge-2.7.2
Changeset: r51669:311b0271907b
Date: 2012-01-22 23:32 +0100
http://bitbucket.org/pypy/pypy/changeset/311b0271907b/
Log: Buffered IO retries read() and write() when the raw stream raises
errno=EINTR.
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,9 +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)
+def trap_eintr(space, error):
+ # Return True if an EnvironmentError with errno == EINTR is set
+ if not error.match(space, space.w_EnvironmentError):
+ return False
+ try:
+ w_value = error.get_w_value(space)
+ w_errno = space.getattr(w_value, space.wrap("errno"))
+ return space.is_true(
+ space.eq(w_errno, space.wrap(errno.EINTR)))
+ except OperationError:
+ return False
+
+
class BlockingIOError(Exception):
pass
@@ -315,7 +329,16 @@
def _write(self, space, data):
w_data = space.wrap(data)
- w_written = space.call_method(self.w_raw, "write", w_data)
+ while True:
+ try:
+ w_written = space.call_method(self.w_raw, "write", w_data)
+ except OperationError, e:
+ if trap_eintr(space, e):
+ continue # try again
+ raise
+ else:
+ break
+
written = space.getindex_w(w_written, space.w_IOError)
if not 0 <= written <= len(data):
raise OperationError(space.w_IOError, space.wrap(
@@ -481,7 +504,16 @@
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)
+ while True:
+ try:
+ w_size = space.call_method(self.w_raw, "readinto", w_buf)
+ except OperationError, e:
+ if trap_eintr(space, e):
+ continue # try again
+ raise
+ else:
+ break
+
if space.is_w(w_size, space.w_None):
raise BlockingIOError()
size = space.int_w(w_size)
diff --git a/pypy/module/_io/test/test_bufferedio.py b/pypy/module/_io/test/test_bufferedio.py
--- a/pypy/module/_io/test/test_bufferedio.py
+++ b/pypy/module/_io/test/test_bufferedio.py
@@ -191,6 +191,26 @@
f = _io.BufferedReader(raw)
assert repr(f) == '<_io.BufferedReader name=%r>' % (self.tmpfile,)
+ def test_read_interrupted(self):
+ import _io, errno
+ class MockRawIO(_io._RawIOBase):
+ def __init__(self):
+ self.count = 0
+ def readable(self):
+ return True
+ def readinto(self, buf):
+ self.count += 1
+ if self.count < 3:
+ raise IOError(errno.EINTR, "interrupted")
+ else:
+ buf[:3] = "abc"
+ return 3
+ rawio = MockRawIO()
+ bufio = _io.BufferedReader(rawio)
+ r = bufio.read(4)
+ assert r == "abca"
+ assert rawio.count == 4
+
class AppTestBufferedReaderWithThreads(AppTestBufferedReader):
spaceconfig = dict(usemodules=['_io', 'thread'])
@@ -386,6 +406,25 @@
assert bufio.read() is None
assert bufio.read() == ""
+ def test_write_interrupted(self):
+ import _io, errno
+ class MockRawIO(_io._RawIOBase):
+ def __init__(self):
+ self.count = 0
+ def writable(self):
+ return True
+ def write(self, data):
+ self.count += 1
+ if self.count < 3:
+ raise IOError(errno.EINTR, "interrupted")
+ else:
+ return len(data)
+ rawio = MockRawIO()
+ bufio = _io.BufferedWriter(rawio)
+ assert bufio.write("test") == 4
+ bufio.flush()
+ assert rawio.count == 3
+
class AppTestBufferedRWPair:
def test_pair(self):
import _io
More information about the pypy-commit
mailing list