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) + |