diff options
-rw-r--r-- | Changes | 1 | ||||
-rw-r--r-- | eio.c | 110 | ||||
-rw-r--r-- | eio.h | 52 |
3 files changed, 130 insertions, 33 deletions
@@ -24,4 +24,5 @@ TODO: openbsd requites stdint.h for intptr_t - why posix? error codes. - add OS-independent EIO_MT_* and EIO_MS_* flag enums. - add eio_statvfs/eio_fstatvfs. + - add eio_mlock/eio_mlockall and OS-independent MCL_* flag enums. @@ -76,12 +76,15 @@ # include "config.h" # include <sys/time.h> # include <sys/select.h> -# include <sys/mman.h> # include <unistd.h> # include <utime.h> # include <signal.h> # include <dirent.h> +#if _POSIX_MEMLOCK || _POSIX_MAPPED_FILES +# include <sys/mman.h> +#endif + /* POSIX_SOURCE is useless on bsd's, and XOPEN_SOURCE is unreliable there, too */ # if __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ # define _DIRENT_HAVE_D_TYPE /* sigh */ @@ -1394,6 +1397,69 @@ eio__scandir (eio_req *req, etp_worker *self) } } +#ifdef PAGESIZE +# define eio_pagesize() PAGESIZE +#else +static intptr_t +eio_pagesize (void) +{ + static intptr_t page; + + if (!page) + page = sysconf (_SC_PAGESIZE); + + return page; +} +#endif + +static void +eio_page_align (void **addr, size_t *length) +{ + intptr_t mask = eio_pagesize () - 1; + + /* round down addr */ + intptr_t adj = mask & (intptr_t)*addr; + + *addr = (void *)((intptr_t)*addr - adj); + *length += adj; + + /* round up length */ + *length = (*length + mask) & ~mask; +} + +#if !_POSIX_MEMLOCK +# define eio__mlock(a,b) ((errno = ENOSYS), -1) +# define eio__mlockall(a) ((errno = ENOSYS), -1) +#else + +static int +eio__mlock (void *addr, size_t length) +{ + eio_page_align (&addr, &length); + + mlock (addr, length); +} + +static int +eio__mlockall (int flags) +{ + #if __GLIBC__ == 2 && __GLIBC_MINOR__ <= 7 + extern int mallopt (int, int); + mallopt (-6, 238); /* http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=473812 */ + #endif + + if (EIO_MCL_CURRENT != MCL_CURRENT + || EIO_MCL_FUTURE != MCL_FUTURE) + { + flags = 0 + | (flags & EIO_MCL_CURRENT ? MCL_CURRENT : 0) + | (flags & EIO_MCL_FUTURE ? MCL_FUTURE : 0); + } + + mlockall (flags); +} +#endif + #if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO) # define eio__msync(a,b,c) ((errno = ENOSYS), -1) #else @@ -1401,6 +1467,8 @@ eio__scandir (eio_req *req, etp_worker *self) int eio__msync (void *mem, size_t len, int flags) { + eio_page_align (&mem, &len); + if (EIO_MS_ASYNC != MS_SYNC || EIO_MS_INVALIDATE != MS_INVALIDATE || EIO_MS_SYNC != MS_SYNC) @@ -1419,25 +1487,19 @@ eio__msync (void *mem, size_t len, int flags) int eio__mtouch (void *mem, size_t len, int flags) { - intptr_t addr = (intptr_t)mem; - intptr_t end = addr + len; -#ifdef PAGESIZE - const intptr_t page = PAGESIZE; -#else - static intptr_t page; + eio_page_align (&mem, &len); - if (!page) - page = sysconf (_SC_PAGESIZE); -#endif - - /* round down to start of page, although this is probably useless */ - addr &= ~(page - 1); /* assume page size is always a power of two */ + { + intptr_t addr = (intptr_t)mem; + intptr_t end = addr + len; + intptr_t page = eio_pagesize (); - if (addr < end) - if (flags & EIO_MT_MODIFY) /* modify */ - do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len); - else - do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len); + if (addr < end) + if (flags & EIO_MT_MODIFY) /* modify */ + do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len); + else + do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len); + } return 0; } @@ -1623,6 +1685,8 @@ static void eio_execute (etp_worker *self, eio_req *req) 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_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; case EIO_READDIR: eio__scandir (req, self); break; @@ -1718,6 +1782,16 @@ 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_mlock (void *addr, size_t length, int pri, eio_cb cb, void *data) +{ + REQ (EIO_MLOCK); req->ptr2 = addr; req->size = length; SEND; +} + +eio_req *eio_mlockall (int flags, int pri, eio_cb cb, void *data) +{ + REQ (EIO_MLOCKALL); 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; @@ -67,7 +67,8 @@ typedef int (*eio_cb)(eio_req *req); /* for readdir */ /* eio_readdir flags */ -enum { +enum +{ EIO_READDIR_DENTS = 0x01, /* ptr2 contains eio_dirents, not just the (unsorted) names */ EIO_READDIR_DIRS_FIRST = 0x02, /* dirents gets sorted into a good stat() ing order to find directories first */ EIO_READDIR_STAT_ORDER = 0x04, /* dirents gets sorted into a good stat() ing order to quickly stat all files */ @@ -78,7 +79,8 @@ enum { }; /* using "typical" values in the hope that the compiler will do something sensible */ -enum eio_dtype { +enum eio_dtype +{ EIO_DT_UNKNOWN = 0, EIO_DT_FIFO = 1, EIO_DT_CHR = 2, @@ -98,7 +100,8 @@ enum eio_dtype { EIO_DT_MAX = 15 /* highest DT_VALUE ever, hopefully */ }; -struct eio_dirent { +struct eio_dirent +{ int nameofs; /* offset of null-terminated name string in (char *)req->ptr2 */ unsigned short namelen; /* size of filename without trailing 0 */ unsigned char type; /* one of EIO_DT_* */ @@ -107,7 +110,8 @@ struct eio_dirent { }; /* eio_msync flags */ -enum { +enum +{ EIO_MS_ASYNC = 1, EIO_MS_INVALIDATE = 2, EIO_MS_SYNC = 4 @@ -115,13 +119,15 @@ enum { /* eio_mtouch flags */ -enum { +enum +{ EIO_MT_MODIFY = 1 }; /* eio_sync_file_range flags */ -enum { +enum +{ EIO_SYNC_FILE_RANGE_WAIT_BEFORE = 1, EIO_SYNC_FILE_RANGE_WRITE = 2, EIO_SYNC_FILE_RANGE_WAIT_AFTER = 4 @@ -131,7 +137,8 @@ typedef double eio_tstamp; /* feel free to use double in your code directly */ /* the eio request structure */ -enum { +enum +{ EIO_CUSTOM, EIO_OPEN, EIO_CLOSE, EIO_DUP2, EIO_READ, EIO_WRITE, @@ -144,6 +151,7 @@ enum { EIO_CHOWN, EIO_FCHOWN, EIO_SYNC, EIO_FSYNC, EIO_FDATASYNC, EIO_MSYNC, EIO_MTOUCH, EIO_SYNC_FILE_RANGE, + EIO_MLOCK, EIO_MLOCKALL, EIO_UNLINK, EIO_RMDIR, EIO_MKDIR, EIO_RENAME, EIO_MKNOD, EIO_READDIR, EIO_LINK, EIO_SYMLINK, EIO_READLINK, @@ -151,6 +159,21 @@ enum { EIO_BUSY }; +/* mlockall constants */ +enum +{ + EIO_MCL_CURRENT = 1, + EIO_MCL_FUTURE = 2, +}; + +/* request priorities */ + +enum { + EIO_PRI_MIN = -4, + EIO_PRI_MAX = 4, + EIO_PRI_DEFAULT = 0, +}; + /* eio request structure */ /* this structure is mostly read-only */ /* when initialising it, all members must be zero-initialised */ @@ -160,14 +183,14 @@ struct eio_req ssize_t result; /* result of syscall, e.g. result = read (... */ off_t offs; /* read, write, truncate, readahead, sync_file_range: file offset */ - size_t size; /* read, write, readahead, sendfile, msync, sync_file_range: length */ + size_t size; /* read, write, readahead, sendfile, msync, mlock, sync_file_range: length */ void *ptr1; /* all applicable requests: pathname, old name; readdir: optional eio_dirents */ void *ptr2; /* all applicable requests: new name or memory buffer; readdir: name strings */ eio_tstamp nv1; /* utime, futime: atime; busy: sleep time */ eio_tstamp nv2; /* utime, futime: mtime */ int type; /* EIO_xxx constant ETP */ - int int1; /* all applicable requests: file descriptor; sendfile: output fd; open, msync, readdir: flags */ + int int1; /* all applicable requests: file descriptor; sendfile: output fd; open, msync, mlockall, readdir: flags */ 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 */ @@ -185,7 +208,7 @@ struct eio_req eio_req *grp, *grp_prev, *grp_next, *grp_first; /* private */ }; -/* _private_ flags */ +/* _private_ request flags */ enum { EIO_FLAG_CANCELLED = 0x01, /* request was cancelled */ EIO_FLAG_PTR1_FREE = 0x02, /* need to free(ptr1) */ @@ -193,11 +216,8 @@ enum { EIO_FLAG_GROUPADD = 0x08 /* some request was added to the group */ }; -enum { - EIO_PRI_MIN = -4, - EIO_PRI_MAX = 4, - EIO_PRI_DEFAULT = 0, -}; +/* undocumented/unsupported/private helper */ +/*void eio_page_align (void **addr, size_t *length);*/ /* returns < 0 on error, errno set * need_poll, if non-zero, will be called when results are available @@ -238,6 +258,8 @@ 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_mlock (void *addr, size_t length, int pri, eio_cb cb, void *data); +eio_req *eio_mlockall (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); |