diff -r 8ec4acfdb851 Include/fileutils.h --- a/Include/fileutils.h Wed Apr 01 11:09:43 2015 +0200 +++ b/Include/fileutils.h Wed Apr 01 11:42:21 2015 +0200 @@ -84,6 +84,11 @@ PyAPI_FUNC(Py_ssize_t) _Py_write( const void *buf, size_t count); +PyAPI_FUNC(Py_ssize_t) _Py_write_noraise( + int fd, + const void *buf, + size_t count); + #ifdef HAVE_READLINK PyAPI_FUNC(int) _Py_wreadlink( const wchar_t *path, diff -r 8ec4acfdb851 Python/fileutils.c --- a/Python/fileutils.c Wed Apr 01 11:09:43 2015 +0200 +++ b/Python/fileutils.c Wed Apr 01 11:42:21 2015 +0200 @@ -667,7 +667,8 @@ int error on error. On POSIX, set errno on error. Fill status and return 0 on success. - The GIL must be held. */ + Release the GIL to call GetFileType() and GetFileInformationByHandle(), or + to call fstat(). The caller must hold the GIL. */ int _Py_fstat(int fd, struct _Py_stat_struct *status) { @@ -968,7 +969,7 @@ static int When interrupted by a signal (open() fails with EINTR), retry the syscall, except if the Python signal handler raises an exception. - The GIL must be held. */ + Release the GIL to call open(). The caller must hold the GIL. */ int _Py_open(const char *pathname, int flags) { @@ -1054,7 +1055,8 @@ FILE* When interrupted by a signal (open() fails with EINTR), retry the syscall, except if the Python signal handler raises an exception. - The GIL must be held. */ + Release the GIL to call _wfopen() or fopen(). The caller must hold + the GIL. */ FILE* _Py_fopen_obj(PyObject *path, const char *mode) { @@ -1124,18 +1126,18 @@ FILE* } /* Read count bytes from fd into buf. - * - * On success, return the number of read bytes, it can be lower than count. - * If the current file offset is at or past the end of file, no bytes are read, - * and read() returns zero. - * - * 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. */ + + On success, return the number of read bytes, it can be lower than count. + If the current file offset is at or past the end of file, no bytes are read, + and read() returns zero. + + 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). + + Release the GIL to call read(). The caller must hold the GIL. */ Py_ssize_t _Py_read(int fd, void *buf, size_t count) { @@ -1200,34 +1202,20 @@ Py_ssize_t return n; } -/* Write count bytes of buf into fd. - * - * -On success, return the number of written 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, const void *buf, size_t count) +static Py_ssize_t +_Py_write_impl(int fd, const void *buf, size_t count, int gil_held) { Py_ssize_t n; int err; int async_err = 0; - /* _Py_write() must not be called with an exception set, otherwise the - * caller may think that write() was interrupted by a signal and the signal - * handler raised an exception. */ - assert(!PyErr_Occurred()); - if (!_PyVerify_fd(fd)) { - /* save/restore errno because PyErr_SetFromErrno() can modify it */ - err = errno; - PyErr_SetFromErrno(PyExc_OSError); - errno = err; + if (gil_held) { + /* save/restore errno because PyErr_SetFromErrno() can modify it */ + err = errno; + PyErr_SetFromErrno(PyExc_OSError); + errno = err; + } return -1; } @@ -1249,30 +1237,45 @@ Py_ssize_t } #endif - do { - Py_BEGIN_ALLOW_THREADS - errno = 0; + if (gil_held) { + do { + Py_BEGIN_ALLOW_THREADS + errno = 0; #ifdef MS_WINDOWS - n = write(fd, buf, (int)count); + n = write(fd, buf, (int)count); #else - n = write(fd, buf, count); + n = write(fd, buf, count); #endif - /* save/restore errno because PyErr_CheckSignals() - * and PyErr_SetFromErrno() can modify it */ - err = errno; - Py_END_ALLOW_THREADS - } while (n < 0 && errno == EINTR && - !(async_err = PyErr_CheckSignals())); + /* save/restore errno because PyErr_CheckSignals() + * and PyErr_SetFromErrno() can modify it */ + err = errno; + Py_END_ALLOW_THREADS + } while (n < 0 && err == EINTR && + !(async_err = PyErr_CheckSignals())); + } + else { + do { + errno = 0; +#ifdef MS_WINDOWS + n = write(fd, buf, (int)count); +#else + n = write(fd, buf, count); +#endif + err = errno; + } while (n < 0 && err == EINTR); + } if (async_err) { /* write() was interrupted by a signal (failed with EINTR) - * and the Python signal handler raised an exception */ + and the Python signal handler raised an exception (if gil_held is + nonzero). */ errno = err; - assert(errno == EINTR && PyErr_Occurred()); + assert(errno == EINTR && (!gil_held || PyErr_Occurred())); return -1; } if (n < 0) { - PyErr_SetFromErrno(PyExc_OSError); + if (gil_held) + PyErr_SetFromErrno(PyExc_OSError); errno = err; return -1; } @@ -1280,6 +1283,40 @@ Py_ssize_t return n; } +/* Write count bytes of buf into fd. + + On success, return the number of written 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). + + Release the GIL to call write(). The caller must hold the GIL. */ +Py_ssize_t +_Py_write(int fd, const void *buf, size_t count) +{ + /* _Py_write() must not be called with an exception set, otherwise the + * caller may think that write() was interrupted by a signal and the signal + * handler raised an exception. */ + assert(!PyErr_Occurred()); + + return _Py_write_impl(fd, buf, count, 1); +} + +/* Write count bytes of buf into fd. + * + * On success, return the number of written bytes, it can be lower than count + * including 0. On set errno and return -1. + * + * When interrupted by a signal (write() fails with EINTR), retry the syscall + * without calling the Python signal handler. */ +Py_ssize_t +_Py_write_noraise(int fd, const void *buf, size_t count) +{ + return _Py_write_impl(fd, buf, count, 0); +} + #ifdef HAVE_READLINK /* Read value of symbolic link. Encode the path to the locale encoding, decode