diff -r 5f90ef1df157 Include/fileutils.h --- a/Include/fileutils.h Wed Mar 18 16:05:32 2015 +0100 +++ b/Include/fileutils.h Thu Mar 19 14:32:52 2015 +0100 @@ -80,6 +80,16 @@ PyAPI_FUNC(FILE*) _Py_fopen_obj( PyObject *path, const char *mode); +PyAPI_FUNC(Py_ssize_t) _Py_read( + int fd, + void *buf, + size_t count); + +PyAPI_FUNC(Py_ssize_t) _Py_write( + int fd, + void *buf, + size_t count); + #ifdef HAVE_READLINK PyAPI_FUNC(int) _Py_wreadlink( const wchar_t *path, diff -r 5f90ef1df157 Modules/_io/fileio.c --- a/Modules/_io/fileio.c Wed Mar 18 16:05:32 2015 +0100 +++ b/Modules/_io/fileio.c Thu Mar 19 14:32:52 2015 +0100 @@ -570,8 +570,8 @@ static PyObject * fileio_readinto(fileio *self, PyObject *args) { Py_buffer pbuf; - Py_ssize_t n, len; - int err, async_err = 0; + Py_ssize_t n; + int err; if (self->fd < 0) return err_closed(); @@ -581,36 +581,15 @@ fileio_readinto(fileio *self, PyObject * if (!PyArg_ParseTuple(args, "w*", &pbuf)) return NULL; - if (_PyVerify_fd(self->fd)) { - len = pbuf.len; -#ifdef MS_WINDOWS - if (len> INT_MAX) - len = INT_MAX; -#endif - - do { - Py_BEGIN_ALLOW_THREADS - errno = 0; -#ifdef MS_WINDOWS - n = read(self->fd, pbuf.buf, (int)len); -#else - n = read(self->fd, pbuf.buf, len); -#endif - Py_END_ALLOW_THREADS - } while (n < 0 && errno == EINTR && - !(async_err = PyErr_CheckSignals())); - - if (async_err) - return NULL; - } else - n = -1; + n = _Py_read(self->fd, pbuf.buf, pbuf.len); err = errno; PyBuffer_Release(&pbuf); - if (n < 0) { - if (err == EAGAIN) + + if (n == -1) { + if (err == EAGAIN) { + PyErr_Clear(); Py_RETURN_NONE; - errno = err; - PyErr_SetFromErrno(PyExc_IOError); + } return NULL; } @@ -645,9 +624,8 @@ fileio_readall(fileio *self) Py_off_t pos, end; PyObject *result; Py_ssize_t bytes_read = 0; - Py_ssize_t len, n; + Py_ssize_t n; size_t bufsize; - int async_err = 0; if (self->fd < 0) return err_closed(); @@ -695,36 +673,22 @@ fileio_readall(fileio *self) } } - len = bufsize - bytes_read; -#ifdef MS_WINDOWS - if (len> INT_MAX) - len = INT_MAX; -#endif - do { - Py_BEGIN_ALLOW_THREADS - errno = 0; -#ifdef MS_WINDOWS - n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)len); -#else - n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, len); -#endif - Py_END_ALLOW_THREADS - } while (n < 0 && errno == EINTR && - !(async_err = PyErr_CheckSignals())); + n = _Py_read(self->fd, + PyBytes_AS_STRING(result) + bytes_read, + bufsize - bytes_read); - if (async_err) - return NULL; if (n == 0) break; - if (n < 0) { - if (errno == EAGAIN) { + if (n == -1) { + /* copy errno because Py_DECREF() can indirectly modify it */ + int err = errno; + Py_DECREF(result); + if (err == EAGAIN) { + PyErr_Clear(); if (bytes_read> 0) break; - Py_DECREF(result); Py_RETURN_NONE; } - Py_DECREF(result); - PyErr_SetFromErrno(PyExc_IOError); return NULL; } bytes_read += n; @@ -756,7 +720,6 @@ fileio_read(fileio *self, PyObject *args char *ptr; Py_ssize_t n; Py_ssize_t size = -1; - int async_err = 0; PyObject *bytes; if (self->fd < 0) @@ -767,44 +730,35 @@ fileio_read(fileio *self, PyObject *args if (!PyArg_ParseTuple(args, "|O&", &_PyIO_ConvertSsize_t, &size)) return NULL; - if (size < 0) { + if (size < 0) return fileio_readall(self); - } #ifdef MS_WINDOWS - if (size> INT_MAX) + if (size> 32767 && isatty(self->fd)) { + /* Issue #11395: the Windows console returns an error (12: not + enough space error) on writing into stdout if stdout mode is + binary and the length is greater than 66,000 bytes (or less, + depending on heap usage). */ + size = 32767; + } + else if (size> INT_MAX) size = INT_MAX; #endif + bytes = PyBytes_FromStringAndSize(NULL, size); if (bytes == NULL) return NULL; ptr = PyBytes_AS_STRING(bytes); - if (_PyVerify_fd(self->fd)) { - do { - Py_BEGIN_ALLOW_THREADS - errno = 0; -#ifdef MS_WINDOWS - n = read(self->fd, ptr, (int)size); -#else - n = read(self->fd, ptr, size); -#endif - Py_END_ALLOW_THREADS - } while (n < 0 && errno == EINTR && - !(async_err = PyErr_CheckSignals())); - - if (async_err) - return NULL; - } else - n = -1; - - if (n < 0) { + n = _Py_read(self->fd, ptr, size); + if (n == -1) { + /* copy errno because Py_DECREF() can indirectly modify it */ int err = errno; Py_DECREF(bytes); - if (err == EAGAIN) + if (err == EAGAIN) { + PyErr_Clear(); Py_RETURN_NONE; - errno = err; - PyErr_SetFromErrno(PyExc_IOError); + } return NULL; } @@ -822,8 +776,8 @@ static PyObject * fileio_write(fileio *self, PyObject *args) { Py_buffer pbuf; - Py_ssize_t n, len; - int err, async_err = 0; + Py_ssize_t n; + int err; if (self->fd < 0) return err_closed(); @@ -833,44 +787,15 @@ fileio_write(fileio *self, PyObject *arg if (!PyArg_ParseTuple(args, "y*", &pbuf)) return NULL; - if (_PyVerify_fd(self->fd)) { - len = pbuf.len; -#ifdef MS_WINDOWS - if (len> 32767 && isatty(self->fd)) { - /* Issue #11395: the Windows console returns an error (12: not - enough space error) on writing into stdout if stdout mode is - binary and the length is greater than 66,000 bytes (or less, - depending on heap usage). */ - len = 32767; - } else if (len> INT_MAX) - len = INT_MAX; -#endif - - do { - Py_BEGIN_ALLOW_THREADS - errno = 0; -#ifdef MS_WINDOWS - n = write(self->fd, pbuf.buf, (int)len); -#else - n = write(self->fd, pbuf.buf, len); -#endif - Py_END_ALLOW_THREADS - } while (n < 0 && errno == EINTR && - !(async_err = PyErr_CheckSignals())); - - if (async_err) - return NULL; - } else - n = -1; + n = _Py_write(self->fd, pbuf.buf, pbuf.len); err = errno; - PyBuffer_Release(&pbuf); if (n < 0) { - if (err == EAGAIN) + if (err == EAGAIN) { + PyErr_Clear(); Py_RETURN_NONE; - errno = err; - PyErr_SetFromErrno(PyExc_IOError); + } return NULL; } diff -r 5f90ef1df157 Modules/posixmodule.c --- a/Modules/posixmodule.c Wed Mar 18 16:05:32 2015 +0100 +++ b/Modules/posixmodule.c Thu Mar 19 14:32:52 2015 +0100 @@ -11207,7 +11207,6 @@ os_read_impl(PyModuleDef *module, int fd /*[clinic end generated code: output=1f3bc27260a24968 input=1df2eaa27c0bf1d3]*/ { Py_ssize_t n; - int async_err = 0; PyObject *buffer; if (length < 0) { @@ -11217,27 +11216,14 @@ os_read_impl(PyModuleDef *module, int fd if (!_PyVerify_fd(fd)) return posix_error(); -#ifdef MS_WINDOWS - #define READ_CAST (int) - if (length> INT_MAX) - length = INT_MAX; -#else - #define READ_CAST -#endif - buffer = PyBytes_FromStringAndSize((char *)NULL, length); if (buffer == NULL) return NULL; - do { - Py_BEGIN_ALLOW_THREADS - n = read(fd, PyBytes_AS_STRING(buffer), READ_CAST length); - Py_END_ALLOW_THREADS - } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); - - if (n < 0) { + n = _Py_read(fd, PyBytes_AS_STRING(buffer), length); + if (n == -1) { Py_DECREF(buffer); - return (!async_err) ? posix_error() : NULL; + return NULL; } if (n != length) @@ -11541,33 +11527,7 @@ static Py_ssize_t os_write_impl(PyModuleDef *module, int fd, Py_buffer *data) /*[clinic end generated code: output=aeb96acfdd4d5112 input=3207e28963234f3c]*/ { - Py_ssize_t size; - int async_err = 0; - Py_ssize_t len = data->len; - - if (!_PyVerify_fd(fd)) { - posix_error(); - return -1; - } - - do { - Py_BEGIN_ALLOW_THREADS -#ifdef MS_WINDOWS - if (len> INT_MAX) - len = INT_MAX; - size = write(fd, data->buf, (int)len); -#else - size = write(fd, data->buf, len); -#endif - Py_END_ALLOW_THREADS - } while (size < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); - - if (size < 0) { - if (!async_err) - posix_error(); - return -1; - } - return size; + return _Py_write(fd, data->buf, data->len); } #ifdef HAVE_SENDFILE diff -r 5f90ef1df157 Objects/fileobject.c --- a/Objects/fileobject.c Wed Mar 18 16:05:32 2015 +0100 +++ b/Objects/fileobject.c Thu Mar 19 14:32:52 2015 +0100 @@ -383,26 +383,15 @@ stdprinter_write(PyStdPrinter_Object *se Py_RETURN_NONE; } - if (!PyArg_ParseTuple(args, "s", &c)) { + if (!PyArg_ParseTuple(args, "s", &c)) return NULL; - } - n = strlen(c); - Py_BEGIN_ALLOW_THREADS - errno = 0; -#ifdef MS_WINDOWS - if (n> INT_MAX) - n = INT_MAX; - n = write(self->fd, c, (int)n); -#else - n = write(self->fd, c, n); -#endif - Py_END_ALLOW_THREADS - - if (n < 0) { - if (errno == EAGAIN) + n = _Py_write(self->fd, c, strlen(c)); + if (n == -1) { + if (errno == EAGAIN) { + PyErr_Clear(); Py_RETURN_NONE; - PyErr_SetFromErrno(PyExc_IOError); + } return NULL; } diff -r 5f90ef1df157 Python/fileutils.c --- a/Python/fileutils.c Wed Mar 18 16:05:32 2015 +0100 +++ b/Python/fileutils.c Thu Mar 19 14:32:52 2015 +0100 @@ -1120,6 +1120,149 @@ FILE* return f; } +/* Read count bytes from fd into buf. Result: + * + * - On success, return the number of read bytes, it can be lower than count + * including 0 + * - On error, raise an exception, set errno and return -1. + * + * When interrupted by a signal (read() fails with EINTR), retry the syscall. + * If the Python signal handler raises an exception, the function returns -1 + * (the syscall is not retried). + * + * The GIL must be held. */ +Py_ssize_t +_Py_read(int fd, void *buf, size_t count) +{ + Py_ssize_t n; + int async_err = 0; + + /* _Py_read() must be called with the GIL held to be able to call + PyErr_CheckSignals(). */ + assert(PyGILState_Check()); + + /* _Py_read() must not be called with an exception set, otherwise the + * caller may think that read() was interrupted by a signal and the signal + * handler raised an exception. */ + assert(!PyErr_Occurred()); + + if (!_PyVerify_fd(self->fd)) { + assert(errno == EBADF); + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + +#ifdef MS_WINDOWS + if (count> INT_MAX) { + /* On Windows, the count parameter of read() is an int */ + count = INT_MAX; + } +#else + if (count> PY_SSIZE_T_MAX) { + /* if count is greater than PY_SSIZE_T_MAX, + * read() result is undefined */ + count = PY_SSIZE_T_MAX; + } +#endif + + do { + Py_BEGIN_ALLOW_THREADS + errno = 0; +#ifdef MS_WINDOWS + n = read(fd, buf, (int)count); +#else + n = read(fd, buf, count); +#endif + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); + + if (async_err) { + assert(errno == EINTR && PyErr_Occurred()); + return -1; + } + if (n < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + return n; +} + +/* Write count bytes of buf into fd. Result: + * + * - On success, return the number of read bytes, it can be lower than count + * including 0 + * - On error, raise an exception, set errno and return -1. + * + * When interrupted by a signal (write() fails with EINTR), retry the syscall. + * If the Python signal handler raises an exception, the function returns -1 + * (the syscall is not retried). + * + * The GIL must be held. */ +Py_ssize_t +_Py_write(int fd, void *buf, size_t count) +{ + Py_ssize_t n; + int async_err = 0; + + /* _Py_write() must be called with the GIL held to be able to call + PyErr_CheckSignals(). */ + assert(PyGILState_Check()); + + /* _Py_write() must not be called with an exception set, otherwise the + * caller may think that read() was interrupted by a signal and the signal + * handler raised an exception. */ + assert(!PyErr_Occurred()); + +#ifdef MS_WINDOWS + if (count> 32767 && isatty(self->fd)) { + /* Issue #11395: the Windows console returns an error (12: not + enough space error) on writing into stdout if stdout mode is + binary and the length is greater than 66,000 bytes (or less, + depending on heap usage). */ + count = 32767; + } + else if (count> INT_MAX) + count = INT_MAX; +#else + if (count> PY_SSIZE_T_MAX) { + /* write() should truncate count to PY_SSIZE_T_MAX, but it's safer + * to do it ourself to have a portable behaviour. */ + count = PY_SSIZE_T_MAX; + } +#endif + + if (!_PyVerify_fd(fd)) { + assert(errno == EBADF); + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + do { + Py_BEGIN_ALLOW_THREADS + errno = 0; +#ifdef MS_WINDOWS + n = write(fd, buf, (int)count); +#else + n = write(fd, buf, count); +#endif + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); + + if (async_err) { + assert(errno == EINTR && PyErr_Occurred()); + return -1; + } + if (n < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + return n; +} + #ifdef HAVE_READLINK /* Read value of symbolic link. Encode the path to the locale encoding, decode