diff options
-rw-r--r-- | erts/emulator/drivers/common/efile_drv.c | 26 | ||||
-rw-r--r-- | erts/emulator/drivers/common/erl_efile.h | 2 | ||||
-rw-r--r-- | erts/emulator/drivers/unix/unix_efile.c | 53 |
3 files changed, 44 insertions, 37 deletions
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 98da63f4e3..5d785a75c4 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -421,7 +421,7 @@ struct t_data struct { int out_fd; off_t offset; - size_t nbytes; + Uint64 nbytes; Uint64 written; short flags; struct t_sendfile_hdtl *hdtl; @@ -1728,7 +1728,7 @@ static void invoke_sendfile(void *data) struct t_data *d = (struct t_data *)data; int fd = d->fd; int out_fd = d->c.sendfile.out_fd; - size_t nbytes = d->c.sendfile.nbytes; + Uint64 nbytes = d->c.sendfile.nbytes; int result = 0; d->again = 0; @@ -2197,12 +2197,13 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) free_preadv(data); break; case FILE_SENDFILE: - printf("efile_ready_async: sendfile (d->result_ok == %d)\r\n",d->result_ok); + //printf("efile_ready_async: sendfile (d->result_ok == %d)\r\n",d->result_ok); if (d->result_ok == -1) { desc->sendfile_state = not_sending; reply_error(desc, &d->errInfo); if (sys_info.async_threads != 0) { SET_NONBLOCKING(d->c.sendfile.out_fd); + free_sendfile(data); } else { driver_select(desc->port, (ErlDrvEvent)d->c.sendfile.out_fd, ERL_DRV_USE, 0); @@ -2212,6 +2213,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) reply_Sint64(desc, d->c.sendfile.written); if (sys_info.async_threads != 0) { SET_NONBLOCKING(d->c.sendfile.out_fd); + free_sendfile(data); } else { driver_select(desc->port, (ErlDrvEvent)d->c.sendfile.out_fd, ERL_DRV_USE, 0); @@ -3367,7 +3369,8 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { case FILE_SENDFILE: { struct t_data *d; - Uint32 out_fd, offsetH, offsetL, nbytesH, nbytesL; + Uint32 out_fd, offsetH, offsetL; + Uint64 nbytes; char flags; /* DestFD:32, Offset:64, Bytes:64, @@ -3382,8 +3385,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { || !EV_GET_CHAR(ev, &flags, &p, &q) || !EV_GET_UINT32(ev, &offsetH, &p, &q) || !EV_GET_UINT32(ev, &offsetL, &p, &q) - || !EV_GET_UINT32(ev, &nbytesH, &p, &q) - || !EV_GET_UINT32(ev, &nbytesL, &p, &q)) { + || !EV_GET_UINT64(ev, &nbytes, &p, &q)) { /* Buffer has wrong length to contain all the needed values */ reply_posix_error(desc, EINVAL); goto done; @@ -3410,17 +3412,9 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->c.sendfile.offset = ((off_t) offsetH << 32) | offsetL; #endif - #if SIZEOF_SIZE_T == 4 - if (nbytesH != 0) { - reply_posix_error(desc, EINVAL); - goto done; - } - d->c.sendfile.nbytes = (size_t) nbytesL; - #else - d->c.sendfile.nbytes = ((size_t) nbytesH << 32) | nbytesL; - #endif + d->c.sendfile.nbytes = nbytes; - printf("sendfile(nbytes => %d, offset => %d, flags => %x)\r\n",d->c.sendfile.nbytes,d->c.sendfile.offset, d->c.sendfile.flags); + printf("sendfile(nbytes => %ld, offset => %d, flags => %x)\r\n",d->c.sendfile.nbytes,d->c.sendfile.offset, d->c.sendfile.flags); /* Do HEADER TRAILER stuff by calculating pointer places, not by copying data! */ diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h index e0b8cfca03..8e79b3923a 100644 --- a/erts/emulator/drivers/common/erl_efile.h +++ b/erts/emulator/drivers/common/erl_efile.h @@ -163,4 +163,4 @@ int efile_may_openfile(Efile_error* errInfo, char *name); int efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, Sint64 length, int advise); int efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, - off_t *offset, size_t *nbytes); + off_t *offset, Uint64 *nbytes); diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 61df572a91..911ec63588 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -1469,33 +1469,46 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, } #ifdef HAVE_SENDFILE -#define SENDFILE_CHUNK_SIZE ((1 << 30) - 1) int efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, - off_t *offset, size_t *nbytes) + off_t *offset, Uint64 *nbytes) { + // printf("sendfile(%d,%d,%d,%d)\r\n",out_fd,in_fd,*offset,*nbytes); + Uint64 written = 0; #if defined(__linux__) || (defined(__sun) && defined(__SVR4)) - ssize_t retval, written = 0; - // printf("sendfile(%d,%d,%d,%d)\r\n",out_fd,in_fd,*offset,*nbytes); - if (*nbytes == 0) { - do { - *nbytes = SENDFILE_CHUNK_SIZE; // chunk size - retval = sendfile(out_fd, in_fd, offset, *nbytes); - if (retval > 0) - written += retval; - } while (retval == SENDFILE_CHUNK_SIZE); - } else { - retval = sendfile(out_fd, in_fd, offset, *nbytes); - if (retval > 0) - written = retval; - } +#define SENDFILE_CHUNK_SIZE ((1 << (8*SIZEOF_SIZE_T)) - 1) + ssize_t retval; + do { + // check if *nbytes is 0 or greater than the largest size_t + if (*nbytes == 0 || *nbytes > SENDFILE_CHUNK_SIZE) + retval = sendfile(out_fd, in_fd, offset, SENDFILE_CHUNK_SIZE); + else + retval = sendfile(out_fd, in_fd, offset, *nbytes); + if (retval > 0) { + written += retval; + *nbytes -= retval; + } + } while (retval == SENDFILE_CHUNK_SIZE); *nbytes = written; return check_error(retval == -1 ? -1 : 0, errInfo); #elif defined(DARWIN) - off_t len = *nbytes; - int retval = sendfile(in_fd, out_fd, *offset, &len, NULL, 0); - *offset += len; - *nbytes = len; +#define SENDFILE_CHUNK_SIZE ((1 << (8*SIZEOF_OFF_T)) - 1) + int retval; + off_t len; + do { + // check if *nbytes is 0 or greater than the largest off_t + if(*nbytes > SENDFILE_CHUNK_SIZE) + len = SENDFILE_CHUNK_SIZE; + else + len = *nbytes; + retval = sendfile(in_fd, out_fd, *offset, &len, NULL, 0); + if (retval != -1 || errno == EAGAIN || errno == EINTR) { + *offset += len; + *nbytes -= len; + written += len; + } + } while (len == SENDFILE_CHUNK_SIZE); + *nbytes = written; return check_error(retval, errInfo); #elif defined(__FreeBSD__) || defined(__DragonFly__) off_t len = 0; |