--- IO-AIO/AIO.xs 2005/08/18 16:34:53 1.31 +++ IO-AIO/AIO.xs 2005/08/22 23:20:37 1.32 @@ -7,6 +7,8 @@ #include "autoconf/config.h" +#include + #include #include @@ -15,11 +17,16 @@ #include #include -#include - -typedef void *InputStream; /* hack, but 5.6.1 is simply toooo old ;) */ -typedef void *OutputStream; /* hack, but 5.6.1 is simply toooo old ;) */ -typedef void *InOutStream; /* hack, but 5.6.1 is simply toooo old ;) */ +#if HAVE_SENDFILE +# if __linux +# include +# elif __freebsd +# include +# include +# elif __hpux +# include +# endif +#endif #if __ia64 # define STACKSIZE 65536 @@ -31,6 +38,7 @@ REQ_QUIT, REQ_OPEN, REQ_CLOSE, REQ_READ, REQ_WRITE, REQ_READAHEAD, + REQ_SENDFILE, REQ_STAT, REQ_LSTAT, REQ_FSTAT, REQ_FSYNC, REQ_FDATASYNC, REQ_UNLINK, REQ_RMDIR, @@ -42,13 +50,14 @@ int type; - int fd; + int fd, fd2; off_t offset; size_t length; ssize_t result; mode_t mode; /* open */ int errorno; - SV *data, *callback, *fh; + SV *data, *callback; + SV *fh, *fh2; void *dataptr, *data2ptr; STRLEN dataoffset; @@ -77,6 +86,9 @@ if (req->fh) SvREFCNT_dec (req->fh); + if (req->fh2) + SvREFCNT_dec (req->fh2); + if (req->statdata) Safefree (req->statdata); @@ -418,6 +430,79 @@ } #endif +/* sendfile always needs emulation */ +static ssize_t +sendfile_ (int ofd, int ifd, off_t offset, size_t count) +{ + ssize_t res; + + if (!count) + return 0; + +#if __linux + res = sendfile (ofd, ifd, &offset, 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 (!res && errno == EAGAIN) + res = sbytes; + } + +#elif __hpux + res = sendfile (ofd, ifd, offset, count, 0, 0); + +#else + res = -1; + errno = ENOSYS; +#endif + + if (res < 0 && (errno == ENOSYS || errno == EINVAL || errno == ENOTSOCK)) + { + /* emulate sendfile. this is a major pain in the ass */ + char *buf = malloc (4096); + res = 0; + + for (;;) + { + ssize_t cnt; + + cnt = pread (ifd, buf, 4096, offset); + + if (cnt <= 0) + { + if (cnt && !res) res = -1; + break; + } + + cnt = write (ofd, buf, cnt); + + if (cnt <= 0) + { + if (cnt && !res) res = -1; + break; + } + + offset += cnt; + res += cnt; + } + + { + int errorno = errno; + free (buf); + errno = errorno; + } + } + + return res; +} + /*****************************************************************************/ static void * @@ -458,6 +543,7 @@ case REQ_WRITE: req->result = pwrite (req->fd, req->dataptr, req->length, req->offset); break; case REQ_READAHEAD: req->result = readahead (req->fd, req->offset, req->length); break; + case REQ_SENDFILE: req->result = sendfile_ (req->fd, req->fd2, req->offset, req->length); break; case REQ_STAT: req->result = stat (req->dataptr, req->statdata); break; case REQ_LSTAT: req->result = lstat (req->dataptr, req->statdata); break; @@ -590,9 +676,9 @@ aio_read(fh,offset,length,data,dataoffset,callback=&PL_sv_undef) SV * fh UV offset - IV length + UV length SV * data - IV dataoffset + UV dataoffset SV * callback ALIAS: aio_read = REQ_READ @@ -651,6 +737,29 @@ } void +aio_sendfile(out_fh,in_fh,in_offset,length,callback=&PL_sv_undef) + SV * out_fh + SV * in_fh + UV in_offset + UV length + SV * callback + PROTOTYPE: $$$$;$ + CODE: +{ + dREQ; + + req->type = REQ_SENDFILE; + req->fh = newSVsv (out_fh); + req->fd = PerlIO_fileno (IoIFP (sv_2io (out_fh))); + req->fh2 = newSVsv (in_fh); + req->fd2 = PerlIO_fileno (IoIFP (sv_2io (in_fh))); + req->offset = in_offset; + req->length = length; + + send_req (req); +} + +void aio_readahead(fh,offset,length,callback=&PL_sv_undef) SV * fh UV offset