kqueue: modernize Struct usage for Ruby 2.5.0dev
[sleepy_penguin.git] / ext / sleepy_penguin / sendfile.c
blob887dfb6e3aea175e1761e68eed87185c6bf159c9
1 #include "sleepy_penguin.h"
2 #include <sys/types.h>
3 #include <sys/socket.h>
4 #include <sys/uio.h>
6 #if defined(HAVE_SYS_SENDFILE_H) && !defined(HAVE_BSD_SENDFILE)
7 # include <sys/sendfile.h>
8 #endif
10 #if defined(__linux__) && defined(HAVE_SENDFILE)
11 # define linux_sendfile(in_fd, out_fd, offset, count) \
12 sendfile((in_fd),(out_fd),(offset),(count))
14 /* all good */
15 #elif defined(HAVE_SENDFILE) && \
16 (defined(__FreeBSD__) || defined(__DragonFly__))
18 * make BSD sendfile look like Linux for now...
19 * we can support SF_NODISKIO later
21 static ssize_t linux_sendfile(int sockfd, int filefd, off_t *off, size_t count)
23 off_t sbytes = 0;
24 off_t offset = off ? *off : lseek(filefd, 0, SEEK_CUR);
26 int rc = sendfile(filefd, sockfd, offset, count, NULL, &sbytes, 0);
27 if (sbytes > 0) {
28 if (off)
29 *off += sbytes;
30 else
31 lseek(filefd, sbytes, SEEK_CUR);
32 return (ssize_t)sbytes;
35 return (ssize_t)rc;
37 #else /* emulate sendfile using (read|pread) + write */
38 static ssize_t pread_sendfile(int sockfd, int filefd, off_t *off, size_t count)
40 size_t max_read = 16384;
41 void *buf;
42 ssize_t r;
43 ssize_t w;
45 max_read = count > max_read ? max_read : count;
46 buf = xmalloc(max_read);
48 do {
49 r = off ? pread(filefd, buf, max_read, *off) :
50 read(filefd, buf, max_read);
51 } while (r < 0 && errno == EINTR);
53 if (r <= 0) {
54 int err = errno;
55 xfree(buf);
56 errno = err;
57 return r;
59 w = write(sockfd, buf, r);
60 if (w > 0 && off)
61 *off += w;
62 xfree(buf);
63 return w;
65 # define linux_sendfile(out_fd, in_fd, offset, count) \
66 pread_sendfile((out_fd),(in_fd),(offset),(count))
67 #endif
69 struct sf_args {
70 int dst_fd;
71 int src_fd;
72 off_t *off;
73 size_t count;
76 static VALUE sym_wait_writable;
78 static VALUE nogvl_sf(void *ptr)
80 struct sf_args *a = ptr;
82 return (VALUE)linux_sendfile(a->dst_fd, a->src_fd, a->off, a->count);
85 static VALUE lsf(VALUE mod, VALUE dst, VALUE src, VALUE src_off, VALUE count)
87 off_t off = 0;
88 struct sf_args a;
89 ssize_t bytes;
90 int retried = 0;
92 a.off = NIL_P(src_off) ? NULL : (off = NUM2OFFT(src_off), &off);
93 a.count = NUM2SIZET(count);
94 again:
95 a.src_fd = rb_sp_fileno(src);
96 a.dst_fd = rb_sp_fileno(dst);
97 bytes = (ssize_t)rb_sp_fd_region(nogvl_sf, &a, a.dst_fd);
98 if (bytes < 0) {
99 switch (errno) {
100 case EAGAIN:
101 return sym_wait_writable;
102 case ENOMEM:
103 case ENOBUFS:
104 if (!retried) {
105 rb_gc();
106 retried = 1;
107 goto again;
110 rb_sys_fail("sendfile");
112 return SSIZET2NUM(bytes);
115 void sleepy_penguin_init_sendfile(void)
117 VALUE m = rb_define_module("SleepyPenguin");
118 rb_define_singleton_method(m, "__lsf", lsf, 4);
119 sym_wait_writable = ID2SYM(rb_intern("wait_writable"));