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