aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
authorSteve Vinoski <[email protected]>2015-08-10 08:34:28 -0400
committerLukas Larsson <[email protected]>2015-08-18 16:25:28 +0200
commitba8740af39b7d4c612b2ee55e3bad6fbdcaf1418 (patch)
treee04ea41c953fdfb1af6cb0177fc86e6ca3243b9a /erts
parent61828f77ca2542109ece006d730a4f8fe3300616 (diff)
downloadotp-ba8740af39b7d4c612b2ee55e3bad6fbdcaf1418.tar.gz
otp-ba8740af39b7d4c612b2ee55e3bad6fbdcaf1418.tar.bz2
otp-ba8740af39b7d4c612b2ee55e3bad6fbdcaf1418.zip
Handle ERRNO_BLOCK in fd_driver async functions
Several users on erlang-questions have reported problems with recent releases where output to standard_error causes standard_error_sup to die from receiving an unexpected eagain error. In the fd_driver, change the fd_async() function to handle EINTR, and change fd_ready_async() to handle ERRNO_BLOCK. Add a new test to standard_error_SUITE to generate output to standard_error and ensure that standard_error_sup does not die. Thanks to Kota Uenishi for contributing the test case.
Diffstat (limited to 'erts')
-rw-r--r--erts/emulator/sys/unix/sys.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index b036b20b7b..8d7da3e47e 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -2527,7 +2527,7 @@ fd_async(void *async_data)
SysIOVec *iov0;
SysIOVec *iov;
int iovlen;
- int err;
+ int err = 0;
/* much of this code is stolen from efile_drv:invoke_writev */
driver_pdl_lock(dd->blocking->pdl);
iov0 = driver_peekq(dd->port_num, &iovlen);
@@ -2542,8 +2542,11 @@ fd_async(void *async_data)
memcpy(iov,iov0,iovlen*sizeof(SysIOVec));
driver_pdl_unlock(dd->blocking->pdl);
- res = writev(dd->ofd, iov, iovlen);
- err = errno;
+ do {
+ res = writev(dd->ofd, iov, iovlen);
+ } while (res < 0 && errno == EINTR);
+ if (res < 0)
+ err = errno;
erts_free(ERTS_ALC_T_SYS_WRITE_BUF, iov);
}
@@ -2582,7 +2585,12 @@ void fd_ready_async(ErlDrvData drv_data,
return /* 0; */;
}
} else if (dd->blocking->res < 0) {
- driver_failure_posix(port_num, dd->blocking->err);
+ if (dd->blocking->err == ERRNO_BLOCK) {
+ set_busy_port(port_num, 1);
+ /* still data left to write in queue */
+ driver_async(port_num, &dd->blocking->pkey, fd_async, dd, NULL);
+ } else
+ driver_failure_posix(port_num, dd->blocking->err);
return; /* -1; */
}
return; /* 0; */