Author: Amaury Forgeot d'Arc <amaur...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit