cpython: 19a6bef57490 (original) (raw)

Mercurial > cpython

changeset 77673:19a6bef57490

Fixes 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. [#12268]

Gregory P. Smith greg@krypto.org
date Sun, 24 Jun 2012 00:23:47 -0700
parents 02bcfb7aa2ca(current diff)781b95159954(diff)
children ba6ca42919dd
files 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
diffstat 8 files changed, 295 insertions(+), 15 deletions(-)[+] [-] Lib/test/test_file_eintr.py 236 Lib/test/test_io.py 10 Misc/NEWS 5 Modules/_io/_iomodule.h 5 Modules/_io/bufferedio.c 8 Modules/_io/fileio.c 7 Modules/_io/iobase.c 23 Modules/_io/textio.c 16

line wrap: on

line diff

new file mode 100644 --- /dev/null +++ b/Lib/test/test_file_eintr.py @@ -0,0 +1,236 @@ +# Written to test interrupted system calls interfering with our many buffered +# IO implementations. http://bugs.python.org/issue12268[](#l1.6) +# +# It was suggested that this code could be merged into test_io and the tests +# made to work using the same method as the existing signal tests in test_io. +# I was unable to get single process tests using alarm or setitimer that way +# to reproduce the EINTR problems. This process based test suite reproduces +# the problems prior to the issue12268 patch reliably on Linux and OSX. +# - gregory.p.smith + +import os +import select +import signal +import subprocess +import sys +from test.support import run_unittest +import time +import unittest + +# Test import all of the things we're about to try testing up front. +from _io import FileIO + + +@unittest.skipUnless(os.name == 'posix', 'tests requires a posix system.') +class TestFileIOSignalInterrupt(unittest.TestCase):

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+ + +class TestBufferedIOSignalInterrupt(TestFileIOSignalInterrupt):

+

+ + +class TestTextIOSignalInterrupt(TestFileIOSignalInterrupt):

+

+

+

+ + +def test_main():

+ + +if name == 'main':

--- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -2912,7 +2912,7 @@ class SignalsTest(unittest.TestCase): try: wio = self.io.open(w, **fdopen_kwargs) t.start()

@@ -2957,7 +2957,7 @@ class SignalsTest(unittest.TestCase): r, w = os.pipe() wio = self.io.open(w, **fdopen_kwargs) try:

@@ -2992,7 +2992,7 @@ class SignalsTest(unittest.TestCase): try: rio = self.io.open(r, **fdopen_kwargs) os.write(w, b"foo")

@@ -3036,13 +3036,13 @@ class SignalsTest(unittest.TestCase): t.daemon = True def alarm1(sig, frame): signal.signal(signal.SIGALRM, alarm2)

--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,11 @@ What's New in Python 3.3.0 Beta 1? Core and Builtins ----------------- +- Issue #12268: File readline, readlines and read() or readall() methods

--- a/Modules/_io/_iomodule.h +++ b/Modules/_io/_iomodule.h @@ -57,6 +57,11 @@ extern Py_ssize_t _PyIO_find_line_ending int translated, int universal, PyObject *readnl, int kind, char *start, char *end, Py_ssize_t consumed); +/ Return 1 if an EnvironmentError with errno == EINTR is set (and then

#define DEFAULT_BUFFER_SIZE (8 * 1024) /* bytes */

--- a/Modules/_io/bufferedio.c +++ b/Modules/_io/bufferedio.c @@ -746,8 +746,8 @@ static int clears the error indicator), 0 otherwise. Should only be called when PyErr_Occurred() is true. */ -static int -_trap_eintr(void) +int +_PyIO_trap_eintr(void) { static PyObject *eintr_int = NULL; PyObject *typ, *val, *tb; @@ -1396,7 +1396,7 @@ static Py_ssize_t */ do { res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_readinto, memobj, NULL);

@@ -1850,7 +1850,7 @@ static Py_ssize_t errno = 0; res = PyObject_CallMethodObjArgs(self->raw, _PyIO_str_write, memobj, NULL); errnum = errno;

--- a/Modules/_io/fileio.c +++ b/Modules/_io/fileio.c @@ -670,6 +670,13 @@ fileio_readall(fileio *self) if (n == 0) break; if (n < 0) {

--- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -474,11 +474,15 @@ iobase_readline(PyObject *self, PyObject PyObject *b; if (has_peek) {

-

@@ -511,8 +515,14 @@ iobase_readline(PyObject *self, PyObject } b = _PyObject_CallMethodId(self, &PyId_read, "n", nreadahead);

@@ -827,6 +837,11 @@ rawiobase_readall(PyObject *self, PyObje PyObject *data = _PyObject_CallMethodId(self, &PyId_read, "i", DEFAULT_BUFFER_SIZE); if (!data) {

--- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1560,8 +1560,14 @@ textiowrapper_read(textio self, PyObjec / Keep reading chunks until we have n characters to return */ while (remaining > 0) { res = textiowrapper_read_chunk(self, remaining);

@@ -1728,8 +1734,14 @@ static PyObject * while (!self->decoded_chars || !PyUnicode_GET_LENGTH(self->decoded_chars)) { res = textiowrapper_read_chunk(self, 0);