diff options
| -rw-r--r-- | Changes | 1 | ||||
| -rw-r--r-- | config.h.in | 3 | ||||
| -rw-r--r-- | configure.ac | 3 | ||||
| -rw-r--r-- | eio.c | 43 | ||||
| -rw-r--r-- | eio.h | 20 | ||||
| -rw-r--r-- | eio.pod | 3 | ||||
| -rw-r--r-- | libeio.m4 | 15 | 
7 files changed, 82 insertions, 6 deletions
| @@ -4,6 +4,7 @@ TODO: maybe add mincore support? available on at leats darwin, solaris, linux, f  1.0  	- added msync, mtouch support (untested). +        - added sync_file_range (untested).          - fixed custom support.          - use a more robust feed-add detection method.  	- "outbundled" from IO::AIO. diff --git a/config.h.in b/config.h.in index 28a13ba..5841743 100644 --- a/config.h.in +++ b/config.h.in @@ -36,6 +36,9 @@  /* Define to 1 if you have the <string.h> header file. */  #undef HAVE_STRING_H +/* sync_file_range(2) is available */ +#undef HAVE_SYNC_FILE_RANGE +  /* Define to 1 if you have the <sys/stat.h> header file. */  #undef HAVE_SYS_STAT_H diff --git a/configure.ac b/configure.ac index 4af457d..f55f47a 100644 --- a/configure.ac +++ b/configure.ac @@ -13,6 +13,9 @@ if test "x$GCC" = xyes ; then    CFLAGS="$CFLAGS -O3"  fi +dnl somebody will forgive me +CFLAGS="-D_GNU_SOURCE" +  m4_include([libeio.m4])  AC_CONFIG_FILES([Makefile]) @@ -738,6 +738,8 @@ int eio_poll (void)  /* work around various missing functions */  #if !HAVE_PREADWRITE +# undef pread +# undef pwrite  # define pread  eio__pread  # define pwrite eio__pwrite @@ -776,6 +778,8 @@ eio__pwrite (int fd, void *buf, size_t count, off_t offset)  #ifndef HAVE_FUTIMES +# undef utimes +# undef futimes  # define utimes(path,times)  eio__utimes  (path, times)  # define futimes(fd,times)   eio__futimes (fd, times) @@ -804,10 +808,40 @@ static int eio__futimes (int fd, const struct timeval tv[2])  #endif  #if !HAVE_FDATASYNC -# define fdatasync fsync +# undef fdatasync +# define fdatasync(fd) fsync (fd)  #endif +/* sync_file_range always needs emulation */ +int +eio__sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags) +{ +#if HAVE_SYNC_FILE_RANGE +  int res; + +  if (EIO_SYNC_FILE_RANGE_WAIT_BEFORE   != SYNC_FILE_RANGE_WAIT_BEFORE +      || EIO_SYNC_FILE_RANGE_WRITE      != SYNC_FILE_RANGE_WRITE +      || EIO_SYNC_FILE_RANGE_WAIT_AFTER != SYNC_FILE_RANGE_WAIT_AFTER) +    { +      flags = 0 +         | (flags & EIO_SYNC_FILE_RANGE_WAIT_BEFORE ? SYNC_FILE_RANGE_WAIT_BEFORE : 0) +         | (flags & EIO_SYNC_FILE_RANGE_WRITE       ? SYNC_FILE_RANGE_WRITE       : 0) +         | (flags & EIO_SYNC_FILE_RANGE_WAIT_AFTER  ? SYNC_FILE_RANGE_WAIT_AFTER  : 0); +    } + +  res = sync_file_range (fd, offset, nbytes, flags); + +  if (res != ENOSYS) +    return res; +#endif + +  /* even though we could play tricks with the flags, it's better to always +   * call fdatasync, as thta matches the expectation of it's users best */ +  return fdatasync (fd); +} +  #if !HAVE_READAHEAD +# undef readahead  # define readahead(fd,offset,count) eio__readahead (fd, offset, count, self)  static ssize_t @@ -983,6 +1017,7 @@ eio__scandir (eio_req *req, etp_worker *self)  }  #if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO) +# undef msync  # define msync(a,b,c) ENOSYS  #endif @@ -1187,6 +1222,7 @@ static void eio_execute (etp_worker *self, eio_req *req)        case EIO_FDATASYNC: req->result = fdatasync (req->int1); break;        case EIO_MSYNC:     req->result = msync (req->ptr2, req->size, req->int1); break;        case EIO_MTOUCH:    req->result = eio__mtouch (req->ptr2, req->size, req->int1); break; +      case EIO_SYNC_FILE_RANGE: req->result = eio__sync_file_range (req->int1, req->offs, req->size, req->int2); break;        case EIO_READDIR:   eio__scandir (req, self); break; @@ -1281,6 +1317,11 @@ eio_req *eio_mtouch (void *addr, size_t length, int flags, int pri, eio_cb cb, v    REQ (EIO_MTOUCH); req->ptr2 = addr; req->size = length; req->int1 = flags; SEND;  } +eio_req *eio_sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags, int pri, eio_cb cb, void *data) +{ +  REQ (EIO_SYNC_FILE_RANGE); req->int1 = fd; req->offs = offset; req->size = nbytes; req->int2 = flags; SEND; +} +  eio_req *eio_fdatasync (int fd, int pri, eio_cb cb, void *data)  {    REQ (EIO_FDATASYNC); req->int1 = fd; SEND; @@ -69,12 +69,21 @@ enum {    EIO_UTIME, EIO_FUTIME,    EIO_CHMOD, EIO_FCHMOD,    EIO_CHOWN, EIO_FCHOWN, -  EIO_SYNC, EIO_FSYNC, EIO_FDATASYNC, EIO_MSYNC, EIO_MTOUCH, +  EIO_SYNC, EIO_FSYNC, EIO_FDATASYNC, +  EIO_MSYNC, EIO_MTOUCH, EIO_SYNC_FILE_RANGE,    EIO_UNLINK, EIO_RMDIR, EIO_MKDIR, EIO_RENAME,    EIO_MKNOD, EIO_READDIR,    EIO_LINK, EIO_SYMLINK, EIO_READLINK,    EIO_GROUP, EIO_NOP, -  EIO_BUSY, +  EIO_BUSY +}; + +/* eio_sync_file_range flags */ + +enum { +  EIO_SYNC_FILE_RANGE_WAIT_BEFORE = 1, +  EIO_SYNC_FILE_RANGE_WRITE       = 2, +  EIO_SYNC_FILE_RANGE_WAIT_AFTER  = 4  };  typedef double eio_tstamp; /* feel free to use double in your code directly */ @@ -86,8 +95,8 @@ struct eio_req    eio_req volatile *next; /* private ETP */    ssize_t result;  /* result of syscall, e.g. result = read (... */ -  off_t offs;      /* read, write, truncate, readahead: file offset */ -  size_t size;     /* read, write, readahead, sendfile, msync: length */ +  off_t offs;      /* read, write, truncate, readahead, sync_file_range: file offset */ +  size_t size;     /* read, write, readahead, sendfile, msync, sync_file_range: length */    void *ptr1;      /* all applicable requests: pathname, old name */    void *ptr2;      /* all applicable requests: new name or memory buffer */    eio_tstamp nv1;  /* utime, futime: atime; busy: sleep time */ @@ -95,7 +104,7 @@ struct eio_req    int type;        /* EIO_xxx constant ETP */    int int1;        /* all applicable requests: file descriptor; sendfile: output fd; open, msync: flags */ -  long int2;       /* chown, fchown: uid; sendfile: input fd; open, chmod, mkdir, mknod: file mode */ +  long int2;       /* chown, fchown: uid; sendfile: input fd; open, chmod, mkdir, mknod: file mode, sync_file_range: flags */    long int3;       /* chown, fchown: gid; mknod: dev_t */    int errorno;     /* errno value on syscall return */ @@ -165,6 +174,7 @@ eio_req *eio_fsync     (int fd, int pri, eio_cb cb, void *data);  eio_req *eio_fdatasync (int fd, int pri, eio_cb cb, void *data);  eio_req *eio_msync     (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data);  eio_req *eio_mtouch    (void *addr, size_t length, int flags, int pri, eio_cb cb, void *data); +eio_req *eio_sync_file_range (int fd, off_t offset, size_t nbytes, unsigned int flags, int pri, eio_cb cb, void *data);  eio_req *eio_close     (int fd, int pri, eio_cb cb, void *data);  eio_req *eio_readahead (int fd, off_t offset, size_t length, int pri, eio_cb cb, void *data);  eio_req *eio_read      (int fd, void *buf, size_t length, off_t offset, int pri, eio_cb cb, void *data); @@ -238,6 +238,9 @@ C<eio_poll>).  Libeio can be embedded directly into programs. This functionality is not  documented and not (yet) officially supported. +Note that, when including C<libeio.m4>, you are responsible for defining +the compilation environment (C<_LARGEFILE_SOURCE>, C<_GNU_SOURCE> etc.). +  If you need to know how, check the C<IO::AIO> perl module, which does  exactly that. @@ -90,3 +90,18 @@ int main(void)  ],ac_cv_sendfile=yes,ac_cv_sendfile=no)])  test $ac_cv_sendfile = yes && AC_DEFINE(HAVE_SENDFILE, 1, sendfile(2) is available and supported) +AC_CACHE_CHECK(for sync_file_range, ac_cv_sync_file_range, [AC_LINK_IFELSE([ +#include <fcntl.h> +int main(void) +{ +   int fd = 0; +   off64_t offset = 1; +   off64_t nbytes = 1; +   unsigned int flags = SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER; +   ssize_t res; +   res = sync_file_range (fd, offset, nbytes, flags); +   return 0; +} +],ac_cv_sync_file_range=yes,ac_cv_sync_file_range=no)]) +test $ac_cv_sync_file_range = yes && AC_DEFINE(HAVE_SYNC_FILE_RANGE, 1, sync_file_range(2) is available) + | 
