Issue #23285: PEP 475 -- Retry system calls failing with EINTR.
diff --git a/Modules/_io/fileio.c b/Modules/_io/fileio.c
index 80af83a..2435513 100644
--- a/Modules/_io/fileio.c
+++ b/Modules/_io/fileio.c
@@ -218,6 +218,7 @@
#ifdef HAVE_FSTAT
struct stat fdfstat;
#endif
+ int async_err = 0;
assert(PyFileIO_Check(oself));
if (self->fd >= 0) {
@@ -360,15 +361,18 @@
errno = 0;
if (opener == Py_None) {
- Py_BEGIN_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
#ifdef MS_WINDOWS
- if (widename != NULL)
- self->fd = _wopen(widename, flags, 0666);
- else
+ if (widename != NULL)
+ self->fd = _wopen(widename, flags, 0666);
+ else
#endif
- self->fd = open(name, flags, 0666);
+ self->fd = open(name, flags, 0666);
- Py_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS
+ } while (self->fd < 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
}
else {
PyObject *fdobj;
@@ -397,7 +401,8 @@
fd_is_own = 1;
if (self->fd < 0) {
- PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
+ if (!async_err)
+ PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
goto error;
}
@@ -550,7 +555,7 @@
{
Py_buffer pbuf;
Py_ssize_t n, len;
- int err;
+ int err, async_err = 0;
if (self->fd < 0)
return err_closed();
@@ -562,16 +567,19 @@
if (_PyVerify_fd(self->fd)) {
len = pbuf.len;
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ errno = 0;
#ifdef MS_WINDOWS
- if (len > INT_MAX)
- len = INT_MAX;
- n = read(self->fd, pbuf.buf, (int)len);
+ if (len > INT_MAX)
+ len = INT_MAX;
+ n = read(self->fd, pbuf.buf, (int)len);
#else
- n = read(self->fd, pbuf.buf, len);
+ n = read(self->fd, pbuf.buf, len);
#endif
- Py_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS
+ } while (n < 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
} else
n = -1;
err = errno;
@@ -580,7 +588,8 @@
if (err == EAGAIN)
Py_RETURN_NONE;
errno = err;
- PyErr_SetFromErrno(PyExc_IOError);
+ if (!async_err)
+ PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
@@ -627,6 +636,7 @@
Py_ssize_t bytes_read = 0;
Py_ssize_t n;
size_t bufsize;
+ int async_err = 0;
if (self->fd < 0)
return err_closed();
@@ -673,27 +683,23 @@
return NULL;
}
}
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
- n = bufsize - bytes_read;
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ errno = 0;
+ n = bufsize - bytes_read;
#ifdef MS_WINDOWS
- if (n > INT_MAX)
- n = INT_MAX;
- n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)n);
+ if (n > INT_MAX)
+ n = INT_MAX;
+ n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)n);
#else
- n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, n);
+ n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, n);
#endif
- Py_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS
+ } while (n < 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
if (n == 0)
break;
if (n < 0) {
- if (errno == EINTR) {
- if (PyErr_CheckSignals()) {
- Py_DECREF(result);
- return NULL;
- }
- continue;
- }
if (errno == EAGAIN) {
if (bytes_read > 0)
break;
@@ -701,7 +707,8 @@
Py_RETURN_NONE;
}
Py_DECREF(result);
- PyErr_SetFromErrno(PyExc_IOError);
+ if (!async_err)
+ PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
bytes_read += n;
@@ -723,6 +730,7 @@
char *ptr;
Py_ssize_t n;
Py_ssize_t size = -1;
+ int async_err = 0;
PyObject *bytes;
if (self->fd < 0)
@@ -747,14 +755,17 @@
ptr = PyBytes_AS_STRING(bytes);
if (_PyVerify_fd(self->fd)) {
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ errno = 0;
#ifdef MS_WINDOWS
- n = read(self->fd, ptr, (int)size);
+ n = read(self->fd, ptr, (int)size);
#else
- n = read(self->fd, ptr, size);
+ n = read(self->fd, ptr, size);
#endif
- Py_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS
+ } while (n < 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
} else
n = -1;
@@ -764,7 +775,8 @@
if (err == EAGAIN)
Py_RETURN_NONE;
errno = err;
- PyErr_SetFromErrno(PyExc_IOError);
+ if (!async_err)
+ PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
@@ -783,7 +795,7 @@
{
Py_buffer pbuf;
Py_ssize_t n, len;
- int err;
+ int err, async_err = 0;
if (self->fd < 0)
return err_closed();
@@ -794,24 +806,26 @@
return NULL;
if (_PyVerify_fd(self->fd)) {
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
- len = pbuf.len;
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ errno = 0;
+ 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;
- n = write(self->fd, pbuf.buf, (int)len);
+ 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;
+ n = write(self->fd, pbuf.buf, (int)len);
#else
- n = write(self->fd, pbuf.buf, len);
+ n = write(self->fd, pbuf.buf, len);
#endif
- Py_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS
+ } while (n < 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
} else
n = -1;
err = errno;
@@ -822,7 +836,8 @@
if (err == EAGAIN)
Py_RETURN_NONE;
errno = err;
- PyErr_SetFromErrno(PyExc_IOError);
+ if (!async_err)
+ PyErr_SetFromErrno(PyExc_IOError);
return NULL;
}
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 94df06c..118a380 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -1361,13 +1361,16 @@
posix_fildes_fd(int fd, int (*func)(int))
{
int res;
- Py_BEGIN_ALLOW_THREADS
- res = (*func)(fd);
- Py_END_ALLOW_THREADS
- if (res < 0)
- return posix_error();
- Py_INCREF(Py_None);
- return Py_None;
+ int async_err = 0;
+
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ res = (*func)(fd);
+ Py_END_ALLOW_THREADS
+ } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+ if (res != 0)
+ return (!async_err) ? posix_error() : NULL;
+ Py_RETURN_NONE;
}
@@ -3479,11 +3482,16 @@
/*[clinic end generated code: output=3c19fbfd724a8e0f input=8ab11975ca01ee5b]*/
{
int res;
- Py_BEGIN_ALLOW_THREADS
- res = fchmod(fd, mode);
- Py_END_ALLOW_THREADS
- if (res < 0)
- return posix_error();
+ int async_err = 0;
+
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ res = fchmod(fd, mode);
+ Py_END_ALLOW_THREADS
+ } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+ if (res != 0)
+ return (!async_err) ? posix_error() : NULL;
+
Py_RETURN_NONE;
}
#endif /* HAVE_FCHMOD */
@@ -4104,11 +4112,16 @@
/*[clinic end generated code: output=687781cb7d8974d6 input=3af544ba1b13a0d7]*/
{
int res;
- Py_BEGIN_ALLOW_THREADS
- res = fchown(fd, uid, gid);
- Py_END_ALLOW_THREADS
- if (res < 0)
- return posix_error();
+ int async_err = 0;
+
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ res = fchown(fd, uid, gid);
+ Py_END_ALLOW_THREADS
+ } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+ if (res != 0)
+ return (!async_err) ? posix_error() : NULL;
+
Py_RETURN_NONE;
}
#endif /* HAVE_FCHOWN */
@@ -9602,12 +9615,17 @@
{
pid_t pid;
struct rusage ru;
+ int async_err = 0;
WAIT_TYPE status;
WAIT_STATUS_INT(status) = 0;
- Py_BEGIN_ALLOW_THREADS
- pid = wait3(&status, options, &ru);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ pid = wait3(&status, options, &ru);
+ Py_END_ALLOW_THREADS
+ } while (pid < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+ if (pid < 0)
+ return (!async_err) ? posix_error() : NULL;
return wait_helper(pid, WAIT_STATUS_INT(status), &ru);
}
@@ -9665,15 +9683,21 @@
os_wait4_impl(PyModuleDef *module, pid_t pid, int options)
/*[clinic end generated code: output=20dfb05289d37dc6 input=d11deed0750600ba]*/
{
+ pid_t res;
struct rusage ru;
+ int async_err = 0;
WAIT_TYPE status;
WAIT_STATUS_INT(status) = 0;
- Py_BEGIN_ALLOW_THREADS
- pid = wait4(pid, &status, options, &ru);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ res = wait4(pid, &status, options, &ru);
+ Py_END_ALLOW_THREADS
+ } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+ if (res < 0)
+ return (!async_err) ? posix_error() : NULL;
- return wait_helper(pid, WAIT_STATUS_INT(status), &ru);
+ return wait_helper(res, WAIT_STATUS_INT(status), &ru);
}
#endif /* HAVE_WAIT4 */
@@ -9744,14 +9768,17 @@
{
PyObject *result;
int res;
+ int async_err = 0;
siginfo_t si;
si.si_pid = 0;
- Py_BEGIN_ALLOW_THREADS
- res = waitid(idtype, id, &si, options);
- Py_END_ALLOW_THREADS
- if (res == -1)
- return posix_error();
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ res = waitid(idtype, id, &si, options);
+ Py_END_ALLOW_THREADS
+ } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+ if (res < 0)
+ return (!async_err) ? posix_error() : NULL;
if (si.si_pid == 0)
Py_RETURN_NONE;
@@ -9828,16 +9855,20 @@
os_waitpid_impl(PyModuleDef *module, pid_t pid, int options)
/*[clinic end generated code: output=095a6b00af70b7ac input=0bf1666b8758fda3]*/
{
+ pid_t res;
+ int async_err = 0;
WAIT_TYPE status;
WAIT_STATUS_INT(status) = 0;
- Py_BEGIN_ALLOW_THREADS
- pid = waitpid(pid, &status, options);
- Py_END_ALLOW_THREADS
- if (pid == -1)
- return posix_error();
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ res = waitpid(pid, &status, options);
+ Py_END_ALLOW_THREADS
+ } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+ if (res < 0)
+ return (!async_err) ? posix_error() : NULL;
- return Py_BuildValue("Ni", PyLong_FromPid(pid), WAIT_STATUS_INT(status));
+ return Py_BuildValue("Ni", PyLong_FromPid(res), WAIT_STATUS_INT(status));
}
#elif defined(HAVE_CWAIT)
/* MS C has a variant of waitpid() that's usable for most purposes. */
@@ -9894,15 +9925,19 @@
/*[clinic end generated code: output=c20b95b15ad44a3a input=444c8f51cca5b862]*/
{
int status;
+ Py_intptr_t res;
+ int async_err = 0;
- Py_BEGIN_ALLOW_THREADS
- pid = _cwait(&status, pid, options);
- Py_END_ALLOW_THREADS
- if (pid == -1)
- return posix_error();
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ res = _cwait(&status, pid, options);
+ Py_END_ALLOW_THREADS
+ } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+ if (res != 0)
+ return (!async_err) ? posix_error() : NULL;
/* shift the status left a byte so this is more like the POSIX waitpid */
- return Py_BuildValue(_Py_PARSE_INTPTR "i", pid, status << 8);
+ return Py_BuildValue(_Py_PARSE_INTPTR "i", res, status << 8);
}
#endif
@@ -9943,14 +9978,17 @@
/*[clinic end generated code: output=2a83a9d164e7e6a8 input=03b0182d4a4700ce]*/
{
pid_t pid;
+ int async_err = 0;
WAIT_TYPE status;
WAIT_STATUS_INT(status) = 0;
- Py_BEGIN_ALLOW_THREADS
- pid = wait(&status);
- Py_END_ALLOW_THREADS
- if (pid == -1)
- return posix_error();
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ pid = wait(&status);
+ Py_END_ALLOW_THREADS
+ } while (pid < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+ if (pid < 0)
+ return (!async_err) ? posix_error() : NULL;
return Py_BuildValue("Ni", PyLong_FromPid(pid), WAIT_STATUS_INT(status));
}
@@ -10837,6 +10875,7 @@
/*[clinic end generated code: output=05b68fc4ed5e29c9 input=ad8623b29acd2934]*/
{
int fd;
+ int async_err = 0;
#ifdef O_CLOEXEC
int *atomic_flag_works = &_Py_open_cloexec_works;
@@ -10850,22 +10889,25 @@
flags |= O_CLOEXEC;
#endif
- Py_BEGIN_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
#ifdef MS_WINDOWS
- if (path->wide)
- fd = _wopen(path->wide, flags, mode);
- else
+ if (path->wide)
+ fd = _wopen(path->wide, flags, mode);
+ else
#endif
#ifdef HAVE_OPENAT
- if (dir_fd != DEFAULT_DIR_FD)
- fd = openat(dir_fd, path->narrow, flags, mode);
- else
+ if (dir_fd != DEFAULT_DIR_FD)
+ fd = openat(dir_fd, path->narrow, flags, mode);
+ else
#endif
- fd = open(path->narrow, flags, mode);
- Py_END_ALLOW_THREADS
+ fd = open(path->narrow, flags, mode);
+ Py_END_ALLOW_THREADS
+ } while (fd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
if (fd == -1) {
- PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
+ if (!async_err)
+ PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
return -1;
}
@@ -10924,6 +10966,10 @@
int res;
if (!_PyVerify_fd(fd))
return posix_error();
+ /* We do not want to retry upon EINTR: see http://lwn.net/Articles/576478/
+ * and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
+ * for more details.
+ */
Py_BEGIN_ALLOW_THREADS
res = close(fd);
Py_END_ALLOW_THREADS
@@ -11089,6 +11135,10 @@
if (!_PyVerify_fd_dup2(fd, fd2))
return posix_error();
+ /* dup2() can fail with EINTR if the target FD is already open, because it
+ * then has to be closed. See os_close_impl() for why we don't handle EINTR
+ * upon close(), and therefore below.
+ */
#ifdef MS_WINDOWS
Py_BEGIN_ALLOW_THREADS
res = dup2(fd, fd2);
@@ -11355,6 +11405,7 @@
/*[clinic end generated code: output=1f3bc27260a24968 input=1df2eaa27c0bf1d3]*/
{
Py_ssize_t n;
+ int async_err = 0;
PyObject *buffer;
if (length < 0) {
@@ -11375,13 +11426,16 @@
buffer = PyBytes_FromStringAndSize((char *)NULL, length);
if (buffer == NULL)
return NULL;
- Py_BEGIN_ALLOW_THREADS
- n = read(fd, PyBytes_AS_STRING(buffer), READ_CAST length);
- Py_END_ALLOW_THREADS
+
+ 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) {
Py_DECREF(buffer);
- return posix_error();
+ return (!async_err) ? posix_error() : NULL;
}
if (n != length)
@@ -11515,6 +11569,7 @@
{
int cnt;
Py_ssize_t n;
+ int async_err = 0;
struct iovec *iov;
Py_buffer *buf;
@@ -11529,13 +11584,16 @@
if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_WRITABLE) < 0)
return -1;
- Py_BEGIN_ALLOW_THREADS
- n = readv(fd, iov, cnt);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ n = readv(fd, iov, cnt);
+ Py_END_ALLOW_THREADS
+ } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
iov_cleanup(iov, buf, cnt);
if (n < 0) {
- posix_error();
+ if (!async_err)
+ posix_error();
return -1;
}
@@ -11598,6 +11656,7 @@
/*[clinic end generated code: output=7b62bf6c06e20ae8 input=084948dcbaa35d4c]*/
{
Py_ssize_t n;
+ int async_err = 0;
PyObject *buffer;
if (length < 0) {
@@ -11611,12 +11670,16 @@
Py_DECREF(buffer);
return posix_error();
}
- Py_BEGIN_ALLOW_THREADS
- n = pread(fd, PyBytes_AS_STRING(buffer), length, offset);
- Py_END_ALLOW_THREADS
+
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ n = pread(fd, PyBytes_AS_STRING(buffer), length, offset);
+ Py_END_ALLOW_THREADS
+ } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+
if (n < 0) {
Py_DECREF(buffer);
- return posix_error();
+ return (!async_err) ? posix_error() : NULL;
}
if (n != length)
_PyBytes_Resize(&buffer, n);
@@ -11677,6 +11740,7 @@
/*[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)) {
@@ -11684,17 +11748,21 @@
return -1;
}
- Py_BEGIN_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
#ifdef MS_WINDOWS
- if (len > INT_MAX)
- len = INT_MAX;
- size = write(fd, data->buf, (int)len);
+ if (len > INT_MAX)
+ len = INT_MAX;
+ size = write(fd, data->buf, (int)len);
#else
- size = write(fd, data->buf, len);
+ size = write(fd, data->buf, len);
#endif
- Py_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS
+ } while (size < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
+
if (size < 0) {
- posix_error();
+ if (!async_err)
+ posix_error();
return -1;
}
return size;
@@ -11713,6 +11781,7 @@
{
int in, out;
Py_ssize_t ret;
+ int async_err = 0;
off_t offset;
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__)
@@ -11775,13 +11844,15 @@
}
}
- Py_BEGIN_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
#ifdef __APPLE__
- ret = sendfile(in, out, offset, &sbytes, &sf, flags);
+ ret = sendfile(in, out, offset, &sbytes, &sf, flags);
#else
- ret = sendfile(in, out, offset, len, &sf, &sbytes, flags);
+ ret = sendfile(in, out, offset, len, &sf, &sbytes, flags);
#endif
- Py_END_ALLOW_THREADS
+ Py_END_ALLOW_THREADS
+ } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
if (sf.headers != NULL)
iov_cleanup(sf.headers, hbuf, sf.hdr_cnt);
@@ -11800,7 +11871,7 @@
return posix_error();
}
}
- return posix_error();
+ return (!async_err) ? posix_error() : NULL;
}
goto done;
@@ -11821,21 +11892,26 @@
return NULL;
#ifdef linux
if (offobj == Py_None) {
- Py_BEGIN_ALLOW_THREADS
- ret = sendfile(out, in, NULL, count);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ ret = sendfile(out, in, NULL, count);
+ Py_END_ALLOW_THREADS
+ } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
if (ret < 0)
- return posix_error();
+ return (!async_err) ? posix_error() : NULL;
return Py_BuildValue("n", ret);
}
#endif
if (!Py_off_t_converter(offobj, &offset))
return NULL;
- Py_BEGIN_ALLOW_THREADS
- ret = sendfile(out, in, &offset, count);
- Py_END_ALLOW_THREADS
+
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ ret = sendfile(out, in, &offset, count);
+ Py_END_ALLOW_THREADS
+ } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
if (ret < 0)
- return posix_error();
+ return (!async_err) ? posix_error() : NULL;
return Py_BuildValue("n", ret);
#endif
}
@@ -11891,15 +11967,18 @@
{
STRUCT_STAT st;
int res;
+ int async_err = 0;
- Py_BEGIN_ALLOW_THREADS
- res = FSTAT(fd, &st);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ res = FSTAT(fd, &st);
+ Py_END_ALLOW_THREADS
+ } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
if (res != 0) {
#ifdef MS_WINDOWS
return PyErr_SetFromWindowsErr(0);
#else
- return posix_error();
+ return (!async_err) ? posix_error() : NULL;
#endif
}
@@ -12185,6 +12264,7 @@
{
int cnt;
Py_ssize_t result;
+ int async_err = 0;
struct iovec *iov;
Py_buffer *buf;
@@ -12199,12 +12279,14 @@
return -1;
}
- Py_BEGIN_ALLOW_THREADS
- result = writev(fd, iov, cnt);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ result = writev(fd, iov, cnt);
+ Py_END_ALLOW_THREADS
+ } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
iov_cleanup(iov, buf, cnt);
- if (result < 0)
+ if (result < 0 && !async_err)
posix_error();
return result;
@@ -12275,17 +12357,20 @@
/*[clinic end generated code: output=ec9cc5b2238e96a7 input=19903f1b3dd26377]*/
{
Py_ssize_t size;
+ int async_err = 0;
if (!_PyVerify_fd(fd)) {
posix_error();
return -1;
}
- Py_BEGIN_ALLOW_THREADS
- size = pwrite(fd, buffer->buf, (size_t)buffer->len, offset);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ size = pwrite(fd, buffer->buf, (size_t)buffer->len, offset);
+ Py_END_ALLOW_THREADS
+ } while (size < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
- if (size < 0)
+ if (size < 0 && !async_err)
posix_error();
return size;
}
@@ -12353,18 +12438,21 @@
/*[clinic end generated code: output=b3321927546893d0 input=73032e98a36e0e19]*/
{
int result;
+ int async_err = 0;
- Py_BEGIN_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_MKFIFOAT
- if (dir_fd != DEFAULT_DIR_FD)
- result = mkfifoat(dir_fd, path->narrow, mode);
- else
+ if (dir_fd != DEFAULT_DIR_FD)
+ result = mkfifoat(dir_fd, path->narrow, mode);
+ else
#endif
- result = mkfifo(path->narrow, mode);
- Py_END_ALLOW_THREADS
-
- if (result < 0)
- return posix_error();
+ result = mkfifo(path->narrow, mode);
+ Py_END_ALLOW_THREADS
+ } while (result != 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
+ if (result != 0)
+ return (!async_err) ? posix_error() : NULL;
Py_RETURN_NONE;
}
@@ -12448,18 +12536,21 @@
/*[clinic end generated code: output=f71d54eaf9bb6f1a input=ee44531551a4d83b]*/
{
int result;
+ int async_err = 0;
- Py_BEGIN_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_MKNODAT
- if (dir_fd != DEFAULT_DIR_FD)
- result = mknodat(dir_fd, path->narrow, mode, device);
- else
+ if (dir_fd != DEFAULT_DIR_FD)
+ result = mknodat(dir_fd, path->narrow, mode, device);
+ else
#endif
- result = mknod(path->narrow, mode, device);
- Py_END_ALLOW_THREADS
-
- if (result < 0)
- return posix_error();
+ result = mknod(path->narrow, mode, device);
+ Py_END_ALLOW_THREADS
+ } while (result != 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
+ if (result != 0)
+ return (!async_err) ? posix_error() : NULL;
Py_RETURN_NONE;
}
@@ -12662,12 +12753,16 @@
/*[clinic end generated code: output=62326766cb9b76bf input=63b43641e52818f2]*/
{
int result;
+ int async_err = 0;
- Py_BEGIN_ALLOW_THREADS
- result = ftruncate(fd, length);
- Py_END_ALLOW_THREADS
- if (result < 0)
- return posix_error();
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ result = ftruncate(fd, length);
+ Py_END_ALLOW_THREADS
+ } while (result != 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
+ if (result != 0)
+ return (!async_err) ? posix_error() : NULL;
Py_RETURN_NONE;
}
#endif /* HAVE_FTRUNCATE */
@@ -12805,14 +12900,16 @@
/*[clinic end generated code: output=0cd702d2065c79db input=d7a2ef0ab2ca52fb]*/
{
int result;
+ int async_err = 0;
- Py_BEGIN_ALLOW_THREADS
- result = posix_fallocate(fd, offset, length);
- Py_END_ALLOW_THREADS
- if (result != 0) {
- errno = result;
- return posix_error();
- }
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ result = posix_fallocate(fd, offset, length);
+ Py_END_ALLOW_THREADS
+ } while (result != 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
+ if (result != 0)
+ return (!async_err) ? posix_error() : NULL;
Py_RETURN_NONE;
}
#endif /* HAVE_POSIX_FALLOCATE) && !POSIX_FADVISE_AIX_BUG */
@@ -12883,14 +12980,16 @@
/*[clinic end generated code: output=dad93f32c04dd4f7 input=0fbe554edc2f04b5]*/
{
int result;
+ int async_err = 0;
- Py_BEGIN_ALLOW_THREADS
- result = posix_fadvise(fd, offset, length, advice);
- Py_END_ALLOW_THREADS
- if (result != 0) {
- errno = result;
- return posix_error();
- }
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ result = posix_fadvise(fd, offset, length, advice);
+ Py_END_ALLOW_THREADS
+ } while (result != 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
+ if (result != 0)
+ return (!async_err) ? posix_error() : NULL;
Py_RETURN_NONE;
}
#endif /* HAVE_POSIX_FADVISE && !POSIX_FADVISE_AIX_BUG */
@@ -13745,13 +13844,17 @@
/*[clinic end generated code: output=0e32bf07f946ec0d input=d8122243ac50975e]*/
{
int result;
+ int async_err = 0;
struct statvfs st;
- Py_BEGIN_ALLOW_THREADS
- result = fstatvfs(fd, &st);
- Py_END_ALLOW_THREADS
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ result = fstatvfs(fd, &st);
+ Py_END_ALLOW_THREADS
+ } while (result != 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
if (result != 0)
- return posix_error();
+ return (!async_err) ? posix_error() : NULL;
return _pystatvfs_fromstructstatvfs(st);
}
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 94cf773..5913e65 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -2037,6 +2037,7 @@
PyObject *addr = NULL;
PyObject *res = NULL;
int timeout;
+ int async_err = 0;
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
/* accept4() is available on Linux 2.6.28+ and glibc 2.10 */
static int accept4_works = -1;
@@ -2050,27 +2051,27 @@
return select_error();
BEGIN_SELECT_LOOP(s)
-
- Py_BEGIN_ALLOW_THREADS
- timeout = internal_select_ex(s, 0, interval);
- if (!timeout) {
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ timeout = internal_select_ex(s, 0, interval);
+ if (!timeout) {
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
- if (accept4_works != 0) {
- newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen,
- SOCK_CLOEXEC);
- if (newfd == INVALID_SOCKET && accept4_works == -1) {
- /* On Linux older than 2.6.28, accept4() fails with ENOSYS */
- accept4_works = (errno != ENOSYS);
+ if (accept4_works != 0) {
+ newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen,
+ SOCK_CLOEXEC);
+ if (newfd == INVALID_SOCKET && accept4_works == -1) {
+ /* On Linux older than 2.6.28, accept4() fails with ENOSYS */
+ accept4_works = (errno != ENOSYS);
+ }
}
- }
- if (accept4_works == 0)
- newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
+ if (accept4_works == 0)
+ newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
#else
- newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
+ newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
#endif
- }
- Py_END_ALLOW_THREADS
-
+ }
+ Py_END_ALLOW_THREADS
+ } while (newfd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
if (timeout == 1) {
PyErr_SetString(socket_timeout, "timed out");
return NULL;
@@ -2078,7 +2079,7 @@
END_SELECT_LOOP(s)
if (newfd == INVALID_SOCKET)
- return s->errorhandler();
+ return (!async_err) ? s->errorhandler() : NULL;
#ifdef MS_WINDOWS
if (!SetHandleInformation((HANDLE)newfd, HANDLE_FLAG_INHERIT, 0)) {
@@ -2341,6 +2342,10 @@
{
SOCKET_T fd;
+ /* We do not want to retry upon EINTR: see http://lwn.net/Articles/576478/
+ * and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
+ * for more details.
+ */
if ((fd = s->sock_fd) != -1) {
s->sock_fd = -1;
Py_BEGIN_ALLOW_THREADS
@@ -2513,10 +2518,8 @@
/* Signals are not errors (though they may raise exceptions). Adapted
from PyErr_SetFromErrnoWithFilenameObject(). */
-#ifdef EINTR
if (res == EINTR && PyErr_CheckSignals())
return NULL;
-#endif
return PyLong_FromLong((long) res);
}
@@ -2650,6 +2653,7 @@
{
Py_ssize_t outlen = -1;
int timeout;
+ int async_err = 0;
if (!IS_SELECTABLE(s)) {
select_error();
@@ -2661,18 +2665,20 @@
}
BEGIN_SELECT_LOOP(s)
- Py_BEGIN_ALLOW_THREADS
- timeout = internal_select_ex(s, 0, interval);
- if (!timeout) {
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ timeout = internal_select_ex(s, 0, interval);
+ if (!timeout) {
#ifdef MS_WINDOWS
- if (len > INT_MAX)
- len = INT_MAX;
- outlen = recv(s->sock_fd, cbuf, (int)len, flags);
+ if (len > INT_MAX)
+ len = INT_MAX;
+ outlen = recv(s->sock_fd, cbuf, (int)len, flags);
#else
- outlen = recv(s->sock_fd, cbuf, len, flags);
+ outlen = recv(s->sock_fd, cbuf, len, flags);
#endif
- }
- Py_END_ALLOW_THREADS
+ }
+ Py_END_ALLOW_THREADS
+ } while (outlen < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
if (timeout == 1) {
PyErr_SetString(socket_timeout, "timed out");
@@ -2682,7 +2688,8 @@
if (outlen < 0) {
/* Note: the call to errorhandler() ALWAYS indirectly returned
NULL, so ignore its return value */
- s->errorhandler();
+ if (!async_err)
+ s->errorhandler();
return -1;
}
return outlen;
@@ -2819,6 +2826,7 @@
int timeout;
Py_ssize_t n = -1;
socklen_t addrlen;
+ int async_err = 0;
*addr = NULL;
@@ -2831,21 +2839,23 @@
}
BEGIN_SELECT_LOOP(s)
- Py_BEGIN_ALLOW_THREADS
- memset(&addrbuf, 0, addrlen);
- timeout = internal_select_ex(s, 0, interval);
- if (!timeout) {
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ memset(&addrbuf, 0, addrlen);
+ timeout = internal_select_ex(s, 0, interval);
+ if (!timeout) {
#ifdef MS_WINDOWS
- if (len > INT_MAX)
- len = INT_MAX;
- n = recvfrom(s->sock_fd, cbuf, (int)len, flags,
- (void *) &addrbuf, &addrlen);
+ if (len > INT_MAX)
+ len = INT_MAX;
+ n = recvfrom(s->sock_fd, cbuf, (int)len, flags,
+ (void *) &addrbuf, &addrlen);
#else
- n = recvfrom(s->sock_fd, cbuf, len, flags,
- SAS2SA(&addrbuf), &addrlen);
+ n = recvfrom(s->sock_fd, cbuf, len, flags,
+ SAS2SA(&addrbuf), &addrlen);
#endif
- }
- Py_END_ALLOW_THREADS
+ }
+ Py_END_ALLOW_THREADS
+ } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
if (timeout == 1) {
PyErr_SetString(socket_timeout, "timed out");
@@ -2853,7 +2863,8 @@
}
END_SELECT_LOOP(s)
if (n < 0) {
- s->errorhandler();
+ if (!async_err)
+ s->errorhandler();
return -1;
}
@@ -2993,6 +3004,7 @@
{
ssize_t bytes_received = -1;
int timeout;
+ int async_err = 0;
sock_addr_t addrbuf;
socklen_t addrbuflen;
struct msghdr msg = {0};
@@ -3028,25 +3040,29 @@
}
BEGIN_SELECT_LOOP(s)
- Py_BEGIN_ALLOW_THREADS;
- msg.msg_name = SAS2SA(&addrbuf);
- msg.msg_namelen = addrbuflen;
- msg.msg_iov = iov;
- msg.msg_iovlen = iovlen;
- msg.msg_control = controlbuf;
- msg.msg_controllen = controllen;
- timeout = internal_select_ex(s, 0, interval);
- if (!timeout)
- bytes_received = recvmsg(s->sock_fd, &msg, flags);
- Py_END_ALLOW_THREADS;
- if (timeout == 1) {
- PyErr_SetString(socket_timeout, "timed out");
- goto finally;
- }
+ do {
+ Py_BEGIN_ALLOW_THREADS;
+ msg.msg_name = SAS2SA(&addrbuf);
+ msg.msg_namelen = addrbuflen;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = iovlen;
+ msg.msg_control = controlbuf;
+ msg.msg_controllen = controllen;
+ timeout = internal_select_ex(s, 0, interval);
+ if (!timeout)
+ bytes_received = recvmsg(s->sock_fd, &msg, flags);
+ Py_END_ALLOW_THREADS;
+ if (timeout == 1) {
+ PyErr_SetString(socket_timeout, "timed out");
+ goto finally;
+ }
+ } while (bytes_received < 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
END_SELECT_LOOP(s)
if (bytes_received < 0) {
- s->errorhandler();
+ if (!async_err)
+ s->errorhandler();
goto finally;
}
@@ -3305,6 +3321,7 @@
{
char *buf;
Py_ssize_t len, n = -1;
+ int async_err = 0;
int flags = 0, timeout;
Py_buffer pbuf;
@@ -3319,18 +3336,20 @@
len = pbuf.len;
BEGIN_SELECT_LOOP(s)
- Py_BEGIN_ALLOW_THREADS
- timeout = internal_select_ex(s, 1, interval);
- if (!timeout) {
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ timeout = internal_select_ex(s, 1, interval);
+ if (!timeout) {
#ifdef MS_WINDOWS
- if (len > INT_MAX)
- len = INT_MAX;
- n = send(s->sock_fd, buf, (int)len, flags);
+ if (len > INT_MAX)
+ len = INT_MAX;
+ n = send(s->sock_fd, buf, (int)len, flags);
#else
- n = send(s->sock_fd, buf, len, flags);
+ n = send(s->sock_fd, buf, len, flags);
#endif
- }
- Py_END_ALLOW_THREADS
+ }
+ Py_END_ALLOW_THREADS
+ } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
if (timeout == 1) {
PyBuffer_Release(&pbuf);
PyErr_SetString(socket_timeout, "timed out");
@@ -3340,7 +3359,7 @@
PyBuffer_Release(&pbuf);
if (n < 0)
- return s->errorhandler();
+ return (!async_err) ? s->errorhandler() : NULL;
return PyLong_FromSsize_t(n);
}
@@ -3359,7 +3378,8 @@
{
char *buf;
Py_ssize_t len, n = -1;
- int flags = 0, timeout, saved_errno;
+ int async_err = 0;
+ int flags = 0, timeout;
Py_buffer pbuf;
if (!PyArg_ParseTuple(args, "y*|i:sendall", &pbuf, &flags))
@@ -3391,29 +3411,16 @@
PyErr_SetString(socket_timeout, "timed out");
return NULL;
}
- /* PyErr_CheckSignals() might change errno */
- saved_errno = errno;
- /* We must run our signal handlers before looping again.
- send() can return a successful partial write when it is
- interrupted, so we can't restrict ourselves to EINTR. */
- if (PyErr_CheckSignals()) {
- PyBuffer_Release(&pbuf);
- return NULL;
+ if (n >= 0) {
+ buf += n;
+ len -= n;
}
- if (n < 0) {
- /* If interrupted, try again */
- if (saved_errno == EINTR)
- continue;
- else
- break;
- }
- buf += n;
- len -= n;
- } while (len > 0);
+ } while (len > 0 && (n >= 0 || errno == EINTR) &&
+ !(async_err = PyErr_CheckSignals()));
PyBuffer_Release(&pbuf);
- if (n < 0)
- return s->errorhandler();
+ if (n < 0 || async_err)
+ return (!async_err) ? s->errorhandler() : NULL;
Py_INCREF(Py_None);
return Py_None;
@@ -3439,6 +3446,7 @@
Py_ssize_t len, arglen;
sock_addr_t addrbuf;
int addrlen, n = -1, flags, timeout;
+ int async_err = 0;
flags = 0;
arglen = PyTuple_Size(args);
@@ -3473,20 +3481,22 @@
}
BEGIN_SELECT_LOOP(s)
- Py_BEGIN_ALLOW_THREADS
- timeout = internal_select_ex(s, 1, interval);
- if (!timeout) {
+ do {
+ Py_BEGIN_ALLOW_THREADS
+ timeout = internal_select_ex(s, 1, interval);
+ if (!timeout) {
#ifdef MS_WINDOWS
- if (len > INT_MAX)
- len = INT_MAX;
- n = sendto(s->sock_fd, buf, (int)len, flags,
- SAS2SA(&addrbuf), addrlen);
+ if (len > INT_MAX)
+ len = INT_MAX;
+ n = sendto(s->sock_fd, buf, (int)len, flags,
+ SAS2SA(&addrbuf), addrlen);
#else
- n = sendto(s->sock_fd, buf, len, flags,
- SAS2SA(&addrbuf), addrlen);
+ n = sendto(s->sock_fd, buf, len, flags,
+ SAS2SA(&addrbuf), addrlen);
#endif
- }
- Py_END_ALLOW_THREADS
+ }
+ Py_END_ALLOW_THREADS
+ } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
if (timeout == 1) {
PyBuffer_Release(&pbuf);
@@ -3496,7 +3506,7 @@
END_SELECT_LOOP(s)
PyBuffer_Release(&pbuf);
if (n < 0)
- return s->errorhandler();
+ return (!async_err) ? s->errorhandler() : NULL;
return PyLong_FromSsize_t(n);
}
@@ -3528,6 +3538,7 @@
void *controlbuf = NULL;
size_t controllen, controllen_last;
ssize_t bytes_sent = -1;
+ int async_err = 0;
int addrlen, timeout, flags = 0;
PyObject *data_arg, *cmsg_arg = NULL, *addr_arg = NULL, *data_fast = NULL,
*cmsg_fast = NULL, *retval = NULL;
@@ -3685,19 +3696,23 @@
}
BEGIN_SELECT_LOOP(s)
- Py_BEGIN_ALLOW_THREADS;
- timeout = internal_select_ex(s, 1, interval);
- if (!timeout)
- bytes_sent = sendmsg(s->sock_fd, &msg, flags);
- Py_END_ALLOW_THREADS;
- if (timeout == 1) {
- PyErr_SetString(socket_timeout, "timed out");
- goto finally;
- }
+ do {
+ Py_BEGIN_ALLOW_THREADS;
+ timeout = internal_select_ex(s, 1, interval);
+ if (!timeout)
+ bytes_sent = sendmsg(s->sock_fd, &msg, flags);
+ Py_END_ALLOW_THREADS;
+ if (timeout == 1) {
+ PyErr_SetString(socket_timeout, "timed out");
+ goto finally;
+ }
+ } while (bytes_sent < 0 && errno == EINTR &&
+ !(async_err = PyErr_CheckSignals()));
END_SELECT_LOOP(s)
if (bytes_sent < 0) {
- s->errorhandler();
+ if (!async_err)
+ s->errorhandler();
goto finally;
}
retval = PyLong_FromSsize_t(bytes_sent);