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);