--- libeio/eio.c 2011/05/30 12:56:50 1.65 +++ libeio/eio.c 2011/06/10 12:35:18 1.71 @@ -60,6 +60,12 @@ #include #include +/* intptr_t comes from unistd.h, says POSIX/UNIX/tradition */ +/* intptr_t only comes form stdint.h, says idiot openbsd coder */ +#if HAVE_STDINT_H +# include +#endif + #ifndef EIO_FINISH # define EIO_FINISH(req) ((req)->finish) && !EIO_CANCELLED (req) ? (req)->finish (req) : 0 #endif @@ -938,84 +944,104 @@ static ssize_t eio__sendfile (int ofd, int ifd, off_t offset, size_t count, etp_worker *self) { + ssize_t written = 0; ssize_t res; if (!count) return 0; + for (;;) + { #if HAVE_SENDFILE # if __linux - res = sendfile (ofd, ifd, &offset, count); + off_t soffset = offset; + res = sendfile (ofd, ifd, &soffset, count); # elif __FreeBSD__ - /* - * Of course, the freebsd sendfile is a dire hack with no thoughts - * wasted on making it similar to other I/O functions. - */ - { - off_t sbytes; - res = sendfile (ifd, ofd, offset, count, 0, &sbytes, 0); - - #if 0 /* according to the manpage, this is correct, but broken behaviour */ - /* freebsd' sendfile will return 0 on success */ - /* freebsd 8 documents it as only setting *sbytes on EINTR and EAGAIN, but */ - /* not on e.g. EIO or EPIPE - sounds broken */ - if ((res < 0 && (errno == EAGAIN || errno == EINTR) && sbytes) || res == 0) - res = sbytes; - #endif - - /* according to source inspection, this is correct, and useful behaviour */ - if (sbytes) - res = sbytes; - } + /* + * Of course, the freebsd sendfile is a dire hack with no thoughts + * wasted on making it similar to other I/O functions. + */ + off_t sbytes; + res = sendfile (ifd, ofd, offset, count, 0, &sbytes, 0); + + #if 0 /* according to the manpage, this is correct, but broken behaviour */ + /* freebsd' sendfile will return 0 on success */ + /* freebsd 8 documents it as only setting *sbytes on EINTR and EAGAIN, but */ + /* not on e.g. EIO or EPIPE - sounds broken */ + if ((res < 0 && (errno == EAGAIN || errno == EINTR) && sbytes) || res == 0) + res = sbytes; + #endif + + /* according to source inspection, this is correct, and useful behaviour */ + if (sbytes) + res = sbytes; # elif defined (__APPLE__) + off_t sbytes = count; + res = sendfile (ifd, ofd, offset, &sbytes, 0, 0); - { - off_t sbytes = count; - res = sendfile (ifd, ofd, offset, &sbytes, 0, 0); - - /* according to the manpage, sbytes is always valid */ - if (sbytes) - res = sbytes; - } + /* according to the manpage, sbytes is always valid */ + if (sbytes) + res = sbytes; # elif __hpux - res = sendfile (ofd, ifd, offset, count, 0, 0); + res = sendfile (ofd, ifd, offset, count, 0, 0); # elif __solaris - { - struct sendfilevec vec; - size_t sbytes; + struct sendfilevec vec; + size_t sbytes; - vec.sfv_fd = ifd; - vec.sfv_flag = 0; - vec.sfv_off = offset; - vec.sfv_len = count; + vec.sfv_fd = ifd; + vec.sfv_flag = 0; + vec.sfv_off = offset; + vec.sfv_len = count; - res = sendfilev (ofd, &vec, 1, &sbytes); + res = sendfilev (ofd, &vec, 1, &sbytes); - if (res < 0 && sbytes) - res = sbytes; - } + if (res < 0 && sbytes) + res = sbytes; # endif #elif defined (_WIN32) - - /* does not work, just for documentation of what would need to be done */ - { - HANDLE h = TO_SOCKET (ifd); - SetFilePointer (h, offset, 0, FILE_BEGIN); - res = TransmitFile (TO_SOCKET (ofd), h, count, 0, 0, 0, 0); - } + /* does not work, just for documentation of what would need to be done */ + /* actually, cannot be done like this, as TransmitFile changes the file offset, */ + /* libeio guarantees that the file offset does not change, and windows */ + /* has no way to get an independent handle to the same file description */ + HANDLE h = TO_SOCKET (ifd); + SetFilePointer (h, offset, 0, FILE_BEGIN); + res = TransmitFile (TO_SOCKET (ofd), h, count, 0, 0, 0, 0); #else - res = -1; - errno = ENOSYS; + res = -1; + errno = ENOSYS; #endif - if (res < 0 + /* we assume sendfile can copy at least 128mb in one go */ + if (res <= 128 * 1024 * 1024) + { + if (res > 0) + written += res; + + if (written) + return written; + + break; + } + else + { + /* if we requested more, then probably the kernel was lazy */ + written += res; + offset += res; + count -= res; + + if (!count) + return written; + } + } + + if (res < 0 && (errno == ENOSYS || errno == EINVAL || errno == ENOTSOCK /* BSDs */ #ifdef ENOTSUP /* sigh, if the steenking pile called openbsd would only try to at least compile posix code... */ @@ -1519,8 +1545,12 @@ #endif int -eio__mtouch (void *mem, size_t len, int flags) +eio__mtouch (eio_req *req) { + void *mem = req->ptr2; + size_t len = req->size; + int flags = req->int1; + eio_page_align (&mem, &len); { @@ -1530,9 +1560,9 @@ if (addr < end) if (flags & EIO_MT_MODIFY) /* modify */ - do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len); + do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len && !EIO_CANCELLED (req)); else - do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len); + do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len && !EIO_CANCELLED (req)); } return 0; @@ -1716,7 +1746,7 @@ case EIO_FSYNC: req->result = fsync (req->int1); break; case EIO_FDATASYNC: req->result = fdatasync (req->int1); break; case EIO_MSYNC: req->result = eio__msync (req->ptr2, req->size, req->int1); break; - case EIO_MTOUCH: req->result = eio__mtouch (req->ptr2, req->size, req->int1); break; + case EIO_MTOUCH: req->result = eio__mtouch (req); break; case EIO_MLOCK: req->result = eio__mlock (req->ptr2, req->size); break; case EIO_MLOCKALL: req->result = eio__mlockall (req->int1); break; case EIO_SYNC_FILE_RANGE: req->result = eio__sync_file_range (req->int1, req->offs, req->size, req->int2); break; @@ -1770,7 +1800,7 @@ break; case EIO_CUSTOM: - ((void (*)(eio_req *))req->feed) (req); + req->feed (req); break; default: @@ -2001,9 +2031,9 @@ return eio__2path (EIO_RENAME, path, new_path, pri, cb, data); } -eio_req *eio_custom (eio_cb execute, int pri, eio_cb cb, void *data) +eio_req *eio_custom (void (*execute)(eio_req *), int pri, eio_cb cb, void *data) { - REQ (EIO_CUSTOM); req->feed = (void (*)(eio_req *))execute; SEND; + REQ (EIO_CUSTOM); req->feed = execute; SEND; } #endif