diff --git a/configure.in b/configure.in index 8f9e7d0..67f5a54 100644 --- a/configure.in +++ b/configure.in @@ -1144,7 +1144,7 @@ AC_CHECK_HEADERS(limits.h sys/file.h sys/ioctl.h sys/syscall.h\ syscall.h pwd.h grp.h a.out.h utime.h direct.h sys/resource.h \ sys/mkdev.h sys/utime.h xti.h netinet/in_systm.h float.h ieeefp.h \ ucontext.h intrinsics.h langinfo.h locale.h sys/sendfile.h time.h \ - net/socket.h sys/socket.h process.h sys/prctl.h) + net/socket.h sys/socket.h process.h sys/prctl.h sys/uio.h) AC_TYPE_SIZE_T RUBY_CHECK_SIZEOF(size_t, [int long void*], [], [@%:@include ]) @@ -1424,7 +1424,7 @@ AC_CHECK_FUNCS(fmod killpg wait4 waitpid fork spawnv syscall __syscall chroot ge setuid setgid daemon select_large_fdset setenv unsetenv\ mktime timegm gmtime_r clock_gettime gettimeofday poll ppoll\ pread sendfile shutdown sigaltstack dl_iterate_phdr\ - dup3 pipe2 posix_memalign memalign) + dup3 pipe2 posix_memalign memalign writev) AC_CACHE_CHECK(for unsetenv returns a value, rb_cv_unsetenv_return_value, [AC_TRY_COMPILE([ diff --git a/io.c b/io.c index e7116cd..3173d85 100644 --- a/io.c +++ b/io.c @@ -78,6 +78,10 @@ #include #endif +#ifdef HAVE_SYS_UIO_H +#include +#endif + #if defined(__BEOS__) || defined(__HAIKU__) # ifndef NOFILE # define NOFILE (OPEN_MAX) @@ -840,6 +844,14 @@ struct io_internal_write_struct { size_t capa; }; +#ifdef HAVE_WRITEV +struct io_internal_writev_struct { + int fd; + const struct iovec *iov; + int iovcnt; +}; +#endif + static VALUE internal_read_func(void *ptr) { @@ -854,6 +866,15 @@ internal_write_func(void *ptr) return write(iis->fd, iis->buf, iis->capa); } +#ifdef HAVE_WRITEV +static VALUE +internal_writev_func(void *ptr) +{ + struct io_internal_writev_struct *iis = ptr; + return writev(iis->fd, iis->iov, iis->iovcnt); +} +#endif + static ssize_t rb_read_internal(int fd, void *buf, size_t count) { @@ -876,6 +897,19 @@ rb_write_internal(int fd, const void *buf, size_t count) return (ssize_t)rb_thread_io_blocking_region(internal_write_func, &iis, fd); } +#ifdef HAVE_WRITEV +static ssize_t +rb_writev_internal(int fd, const struct iovec *iov, int iovcnt) +{ + struct io_internal_writev_struct iis; + iis.fd = fd; + iis.iov = iov; + iis.iovcnt = iovcnt; + + return (ssize_t)rb_thread_io_blocking_region(internal_writev_func, &iis, fd); +} +#endif + static long io_writable_length(rb_io_t *fptr, long l) { @@ -1063,6 +1097,43 @@ struct write_arg { int nosync; }; +#ifdef HAVE_WRITEV +static VALUE +io_binwritev_string(VALUE arg) +{ + struct binwrite_arg *p = (struct binwrite_arg *)arg; + rb_io_t *fptr = p->fptr; + long r; + + if (fptr->wbuf.len) { + struct iovec iov[2]; + + iov[0].iov_base = fptr->wbuf.ptr+fptr->wbuf.off; + iov[0].iov_len = fptr->wbuf.len; + iov[1].iov_base = (char *)p->ptr; + iov[1].iov_len = p->length; + + r = rb_writev_internal(fptr->fd, iov, 2); + + if (fptr->wbuf.len <= r) { + r -= fptr->wbuf.len; + fptr->wbuf.off = 0; + fptr->wbuf.len = 0; + } + else { + fptr->wbuf.off += (int)r; + fptr->wbuf.len -= (int)r; + r = 0L; + } + } + else { + long l = io_writable_length(fptr, p->length); + r = rb_write_internal(fptr->fd, p->ptr, l); + } + + return r; +} +#else static VALUE io_binwrite_string(VALUE arg) { @@ -1070,6 +1141,7 @@ io_binwrite_string(VALUE arg) long l = io_writable_length(p->fptr, p->length); return rb_write_internal(p->fptr->fd, p->ptr, l); } +#endif static long io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync) @@ -1088,7 +1160,19 @@ io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync) (fptr->wbuf.ptr && fptr->wbuf.capa <= fptr->wbuf.len + len)) { struct binwrite_arg arg; - /* xxx: use writev to avoid double write if available */ + arg.fptr = fptr; + arg.str = str; +#ifdef HAVE_WRITEV + retry: + arg.ptr = ptr + offset; + arg.length = n; + if (fptr->write_lock) { + r = rb_mutex_synchronize(fptr->write_lock, io_binwritev_string, (VALUE)&arg); + } + else { + r = io_binwritev_string((VALUE)&arg); + } +#else if (fptr->wbuf.len && fptr->wbuf.len+len <= fptr->wbuf.capa) { if (fptr->wbuf.capa < fptr->wbuf.off+fptr->wbuf.len+len) { MEMMOVE(fptr->wbuf.ptr, fptr->wbuf.ptr+fptr->wbuf.off, char, fptr->wbuf.len); @@ -1107,8 +1191,6 @@ io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync) if (fptr->stdio_file != stderr && !rb_thread_fd_writable(fptr->fd)) { rb_io_check_closed(fptr); } - arg.fptr = fptr; - arg.str = str; retry: arg.ptr = ptr + offset; arg.length = n; @@ -1119,6 +1201,7 @@ io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync) long l = io_writable_length(fptr, n); r = rb_write_internal(fptr->fd, ptr+offset, l); } +#endif /* xxx: other threads may modify given string. */ if (r == n) return len; if (0 <= r) { @@ -9373,10 +9456,6 @@ simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count) */ # define USE_SENDFILE -# ifdef HAVE_SYS_UIO_H -# include -# endif - static ssize_t simple_sendfile(int out_fd, int in_fd, off_t *offset, off_t count) {