--- libeio/eio.c 2011/02/15 03:15:16 1.62 +++ libeio/eio.c 2011/06/10 12:35:18 1.71 @@ -37,6 +37,10 @@ * either the BSD or the GPL. */ +#ifndef _WIN32 +# include "config.h" +#endif + #include "eio.h" #ifdef EIO_STACKSIZE @@ -56,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 @@ -73,7 +83,6 @@ /*doh*/ #else -# include "config.h" # include # include # include @@ -935,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... */ @@ -1062,8 +1091,10 @@ static signed char eio_dent_cmp (const eio_dirent *a, const eio_dirent *b) { - return a->score - b->score ? a->score - b->score /* works because our signed char is always 0..100 */ - : a->inode < b->inode ? -1 : a->inode > b->inode ? 1 : 0; + return a->score - b->score ? a->score - b->score /* works because our signed char is always 0..100 */ + : a->inode < b->inode ? -1 + : a->inode > b->inode ? 1 + : 0; } #define EIO_DENT_CMP(i,op,j) eio_dent_cmp (&i, &j) op 0 @@ -1079,8 +1110,8 @@ assert (CHAR_BIT == 8); assert (sizeof (eio_dirent) * 8 < 256); - assert (offsetof (eio_dirent, inode)); /* we use 0 as sentinel */ - assert (offsetof (eio_dirent, score)); /* we use 0 as sentinel */ + assert (offsetof (eio_dirent, inode)); /* we use bit #0 as sentinel */ + assert (offsetof (eio_dirent, score)); /* we use bit #0 as sentinel */ if (size <= EIO_SORT_FAST) return; @@ -1245,6 +1276,7 @@ X_LOCK (wrklock); /* the corresponding closedir is in ETP_WORKER_CLEAR */ self->dirp = dirp = opendir (req->ptr1); + req->flags |= EIO_FLAG_PTR1_FREE | EIO_FLAG_PTR2_FREE; req->ptr1 = dents = flags ? malloc (dentalloc * sizeof (eio_dirent)) : 0; req->ptr2 = names = malloc (namesalloc); @@ -1266,7 +1298,7 @@ req->result = dentoffs; if (flags & EIO_READDIR_STAT_ORDER) - eio_dent_sort (dents, dentoffs, 0, inode_bits); /* sort by inode exclusively */ + eio_dent_sort (dents, dentoffs, flags & EIO_READDIR_DIRS_FIRST ? 7 : 0, inode_bits); else if (flags & EIO_READDIR_DIRS_FIRST) if (flags & EIO_READDIR_FOUND_UNKNOWN) eio_dent_sort (dents, dentoffs, 7, inode_bits); /* sort by score and inode */ @@ -1278,7 +1310,6 @@ /* now partition dirs to the front, and non-dirs to the back */ /* by walking from both sides and swapping if necessary */ - /* also clear score, so it doesn't influence sorting */ while (oth > dir) { if (dir->type == EIO_DT_DIR) @@ -1291,7 +1322,7 @@ } } - /* now sort the dirs only */ + /* now sort the dirs only (dirs all have the same score) */ eio_dent_sort (dents, dir - dents, 0, inode_bits); } @@ -1514,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); { @@ -1525,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; @@ -1711,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; @@ -1765,7 +1800,7 @@ break; case EIO_CUSTOM: - ((void (*)(eio_req *))req->feed) (req); + req->feed (req); break; default: @@ -1996,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