aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/drivers/unix
diff options
context:
space:
mode:
authorTuncer Ayaz <[email protected]>2011-01-13 12:36:14 +0100
committerLukas Larsson <[email protected]>2011-11-29 14:30:35 +0100
commit195e1f19b06095f39a4fb0da46dfab2ec5b10e9a (patch)
tree8f4a8c587b72c3a20d18b4cb6ccd7d1d52eb6286 /erts/emulator/drivers/unix
parent7292c3d9f5285592aa4de996f6f106cd365d7895 (diff)
downloadotp-195e1f19b06095f39a4fb0da46dfab2ec5b10e9a.tar.gz
otp-195e1f19b06095f39a4fb0da46dfab2ec5b10e9a.tar.bz2
otp-195e1f19b06095f39a4fb0da46dfab2ec5b10e9a.zip
Implement file:sendfile
Allow Erlang code to use sendfile() where available by wrapping it as file:sendfile/4 and file:sendfile/2. sendfile(2) - Linux man page: "sendfile() copies data between one file descriptor and another. Because this copying is done within the kernel, sendfile() is more efficient than the combination of read(2) and write(2), which would require transferring data to and from user space."
Diffstat (limited to 'erts/emulator/drivers/unix')
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 4b3934657c..5b001b3819 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -33,6 +33,9 @@
#include <sys/types.h>
#include <sys/uio.h>
#endif
+#if defined(__linux__) || (defined(__sun) && defined(__SVR4))
+#include <sys/sendfile.h>
+#endif
#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__)
#define DARWIN 1
@@ -1464,3 +1467,44 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
return check_error(0, errInfo);
#endif
}
+
+#ifdef HAVE_SENDFILE
+int
+efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
+ off_t *offset, size_t *count)
+{
+#if defined(__linux__) || (defined(__sun) && defined(__SVR4))
+ ssize_t retval = sendfile(out_fd, in_fd, offset, *count);
+ if (retval >= 0) {
+ if (retval != *count) {
+ *count = retval;
+ retval = -1;
+ errno = EAGAIN;
+ } else {
+ *count = retval;
+ }
+ } else if (retval == -1 && (errno == EINTR || errno == EAGAIN)) {
+ *count = 0;
+ }
+ return check_error(retval == -1 ? -1 : 0, errInfo);
+#elif defined(DARWIN)
+ off_t len = *count;
+ int retval = sendfile(in_fd, out_fd, *offset, &len, NULL, 0);
+ *count = len;
+ return check_error(retval, errInfo);
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+ off_t len = 0;
+ int retval = sendfile(in_fd, out_fd, *offset, *count, NULL, &len, 0);
+ *count = len;
+ return check_error(retval, errInfo);
+#endif
+}
+#else /* no sendfile() */
+int
+efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
+ off_t *offset, size_t *count)
+{
+ errno = ENOTSUP;
+ return check_error(-1, errInfo);
+}
+#endif