diff options
author | Steve Vinoski <[email protected]> | 2015-08-10 08:34:28 -0400 |
---|---|---|
committer | Lukas Larsson <[email protected]> | 2015-08-18 16:25:28 +0200 |
commit | ba8740af39b7d4c612b2ee55e3bad6fbdcaf1418 (patch) | |
tree | e04ea41c953fdfb1af6cb0177fc86e6ca3243b9a /erts/emulator/sys | |
parent | 61828f77ca2542109ece006d730a4f8fe3300616 (diff) | |
download | otp-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/emulator/sys')
-rw-r--r-- | erts/emulator/sys/unix/sys.c | 16 |
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; */ |