From d28b74e4bca1ab7fe54ddf4593f5b533bb436b68 Mon Sep 17 00:00:00 2001 From: rswindell <> Date: Wed, 14 Aug 2019 05:59:30 +0000 Subject: [PATCH] Use "Open file description locks" when available (i.e. Linux 3.15 and later) This variation on fcntl() record-locks resolves multiple-thread / forking issue with region locks. No longer falls back to using flock() (whole-file locks), when OFD locks are available and used successfully. At the least, this should provide a performance boost for shared files using region locks (on Linux). No change for Windows (region locks already worked sanely among multiple threads) and other *nixes (that use POSIX fcntl() locks only). --- src/xpdev/filewrap.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/xpdev/filewrap.c b/src/xpdev/filewrap.c index 4e9c91d061..2ebbb74c8f 100644 --- a/src/xpdev/filewrap.c +++ b/src/xpdev/filewrap.c @@ -90,7 +90,11 @@ off_t DLLCALL filelength(int fd) int DLLCALL lock(int fd, off_t pos, off_t len) { #if defined(F_SANERDLCKNO) || !defined(BSD) - struct flock alock; + struct flock alock = {0}; + int cmd = F_SETLK; + #ifdef F_OFD_SETLK + cmd = F_OFD_SETLK; + #endif #ifndef F_SANEWRLCKNO int flags; @@ -107,8 +111,13 @@ int DLLCALL lock(int fd, off_t pos, off_t len) alock.l_start = pos; alock.l_len = (int)len; - if(fcntl(fd, F_SETLK, &alock)==-1 && errno != EINVAL) - return(-1); + int result = fcntl(fd, cmd, &alock); + if(result == -1 && errno != EINVAL) + return -1; + #ifdef F_OFD_SETLK + if(result == 0) + return 0; + #endif #endif #if !defined(F_SANEWRLCKNO) && !defined(__QNX__) && !defined(__solaris__) @@ -125,7 +134,11 @@ int DLLCALL unlock(int fd, off_t pos, off_t len) { #if defined(F_SANEUNLCK) || !defined(BSD) - struct flock alock; + struct flock alock = {0}; + int cmd = F_SETLK; +#ifdef F_OFD_SETLK + cmd = F_OFD_SETLK; +#endif #ifdef F_SANEUNLCK alock.l_type = F_SANEUNLCK; /* remove the lock */ #else @@ -134,8 +147,13 @@ int DLLCALL unlock(int fd, off_t pos, off_t len) alock.l_whence = L_SET; alock.l_start = pos; alock.l_len = (int)len; - if(fcntl(fd, F_SETLK, &alock)==-1 && errno != EINVAL) - return(-1); + int result = fcntl(fd, cmd, &alock); + if(result == -1 && errno != EINVAL) + return -1; +#ifdef F_OFD_SETLK + if(result == 0) + return 0; +#endif #endif #if !defined(F_SANEUNLCK) && !defined(__QNX__) && !defined(__solaris__) @@ -192,7 +210,7 @@ int DLLCALL sopen(const char *fn, int sh_access, int share, ...) int flock_op=LOCK_NB; /* non-blocking */ #endif #if defined(F_SANEWRLCKNO) || !defined(BSD) - struct flock alock; + struct flock alock = {0}; #endif va_list ap; @@ -208,13 +226,17 @@ int DLLCALL sopen(const char *fn, int sh_access, int share, ...) if (share == SH_DENYNO || share == SH_COMPAT) /* no lock needed */ return fd; #if defined(F_SANEWRLCKNO) || !defined(BSD) + int cmd = F_SETLK; +#ifdef F_OFD_SETLK + cmd = F_OFD_SETLK; +#endif /* use fcntl (doesn't work correctly with threads) */ alock.l_type = share; alock.l_whence = L_SET; alock.l_start = 0; alock.l_len = 0; /* lock to EOF */ - if(fcntl(fd, F_SETLK, &alock)==-1 && errno != EINVAL) { /* EINVAL means the file does not support locking */ + if(fcntl(fd, cmd, &alock)==-1 && errno != EINVAL) { /* EINVAL means the file does not support locking */ close(fd); return -1; } -- GitLab