diff options
-rw-r--r-- | erts/emulator/drivers/common/efile_drv.c | 18 | ||||
-rw-r--r-- | erts/emulator/drivers/unix/unix_efile.c | 21 | ||||
-rw-r--r-- | lib/kernel/test/sendfile_SUITE.erl | 19 |
3 files changed, 38 insertions, 20 deletions
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 7a80b382b1..ad0e371950 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -1777,20 +1777,16 @@ static void invoke_sendfile(void *data) d->c.sendfile.written += nbytes; - if (result == 1) { - if (USE_THRDS_FOR_SENDFILE) { - d->result_ok = 0; - } else if (d->c.sendfile.nbytes == 0 && nbytes != 0) { - d->result_ok = 1; - } else if ((d->c.sendfile.nbytes - nbytes) != 0) { - d->result_ok = 1; - d->c.sendfile.nbytes -= nbytes; - } else { - d->result_ok = 0; - } + if (result == 1 || (result == 0 && USE_THRDS_FOR_SENDFILE)) { + d->result_ok = 0; } else if (result == 0 && (d->errInfo.posix_errno == EAGAIN || d->errInfo.posix_errno == EINTR)) { + if ((d->c.sendfile.nbytes - nbytes) != 0) { d->result_ok = 1; + if (d->c.sendfile.nbytes != 0) + d->c.sendfile.nbytes -= nbytes; + } else + d->result_ok = 0; } else { d->result_ok = -1; } diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 796843a735..dfb6cece14 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -1426,6 +1426,14 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, * you would have to emulate it in linux and on BSD/Darwin some complex * calculations have to be made when using a non blocking socket to figure * out how much of the header/file/trailer was sent in each command. + * + * The semantics of the API is this: + * Return value: 1 if all data was sent and the function does not need to + * be called again. 0 if an error occures OR if there is more data which + * has to be sent (EAGAIN or EINTR will be set appropriately) + * + * The amount of data written in a call is returned through nbytes. + * */ int @@ -1446,8 +1454,11 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, *nbytes -= retval; } } while (retval == SENDFILE_CHUNK_SIZE); - *nbytes = written; - return check_error(retval == -1 ? -1 : 0, errInfo); + if (written != 0) { + // -1 is not returned by the linux API so we have to simulate it + retval = -1; + errno = EAGAIN; + } #elif defined(__sun) && defined(__SVR4) && defined(HAVE_SENDFILEV) ssize_t retval; size_t len; @@ -1469,8 +1480,6 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, written += len; } } while (len == SENDFILE_CHUNK_SIZE); - *nbytes = written; - return check_error(retval == -1 ? -1 : 0, errInfo); #elif defined(DARWIN) int retval; off_t len; @@ -1487,8 +1496,6 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, written += len; } } while (len == SENDFILE_CHUNK_SIZE); - *nbytes = written; - return check_error(retval, errInfo); #elif defined(__FreeBSD__) || defined(__DragonFly__) off_t len; int retval; @@ -1504,8 +1511,8 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, written += len; } } while(len == SENDFILE_CHUNK_SIZE); +#endif *nbytes = written; return check_error(retval, errInfo); -#endif } #endif /* HAVE_SENDFILE */ diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl index 5d77305e37..4056b5d121 100644 --- a/lib/kernel/test/sendfile_SUITE.erl +++ b/lib/kernel/test/sendfile_SUITE.erl @@ -26,7 +26,8 @@ all() -> [t_sendfile_small - ,t_sendfile_big + ,t_sendfile_big_all + ,t_sendfile_big_size ,t_sendfile_many_small ,t_sendfile_partial ,t_sendfile_offset @@ -114,7 +115,7 @@ t_sendfile_many_small(Config) when is_list(Config) -> ok = sendfile_send({127,0,0,1}, Send, 0). -t_sendfile_big(Config) when is_list(Config) -> +t_sendfile_big_all(Config) when is_list(Config) -> Filename = proplists:get_value(big_file, Config), Send = fun(Sock) -> @@ -126,6 +127,20 @@ t_sendfile_big(Config) when is_list(Config) -> ok = sendfile_send({127,0,0,1}, Send, 0). +t_sendfile_big_size(Config) -> + Filename = proplists:get_value(big_file, Config), + FileOpts = proplists:get_value(file_opts, Config, []), + + SendAll = fun(Sock) -> + {ok, #file_info{size = Size}} = + file:read_file_info(Filename), + {ok,D} = file:open(Filename,[read|FileOpts]), + {ok, Size} = file:sendfile(D, Sock,0,Size,[]), + Size + end, + + ok = sendfile_send({127,0,0,1}, SendAll, 0). + t_sendfile_partial(Config) -> Filename = proplists:get_value(small_file, Config), FileOpts = proplists:get_value(file_opts, Config, []), |