commit 90b819c6d832046840018ff08b9bc5d0e3b69c37
parent e6c5c984461dc4cec0ef2d68524d6bd457e23853
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date: Sun, 29 Nov 2020 21:02:32 +0000
Revamp lock primitives; prepare for 2.10.0.0 instead of 2.9.4.0
flock() doesn't have a way to test for a lock without taking it.
lockf() doesn't have shared locks.
The only way to have both is fcntl(). So I rewrote all the
locking stuff around fcntl(), and used the opportunity to change
the interface.
The point of changing the interface is to stop having to bother
with the old one, so to hell with compatibility, let's just do a
major bump.
Diffstat:
19 files changed, 101 insertions(+), 237 deletions(-)
diff --git a/NEWS b/NEWS
@@ -1,14 +1,15 @@
Changelog for skalibs.
-In 2.9.4.0
-----------
+In 2.10.0.0
+-----------
- New openc_* functions.
- New function: ipc_bind_reuse_lock(), taking a lock before
unconditionally deleting the socket.
- ipc_bind_reuse() rewritten to use ipc_bind_reuse_lock(),
so it does the right thing instead of clobbering sockets.
- - Complete revamping of the pathexec functions, see exec.h
+ - Complete revamping of the pathexec functions, see exec.h.
+ - Revamping of the locking functions.
In 2.9.3.0
diff --git a/doc/index.html b/doc/index.html
@@ -60,7 +60,7 @@ with a standard C development environment </li>
<h3> Download </h3>
<ul>
- <li> The current released version of skalibs is <a href="skalibs-2.9.4.0.tar.gz">2.9.4.0</a>. </li>
+ <li> The current released version of skalibs is <a href="skalibs-2.10.0.0.tar.gz">2.10.0.0</a>. </li>
<li> Alternatively, you can checkout a copy of the
<a href="//git.skarnet.org/cgi-bin/cgit.cgi/skalibs/">skalibs
git repository</a>:
diff --git a/doc/libstddjb/djbunix.html b/doc/libstddjb/djbunix.html
@@ -202,45 +202,26 @@ with errno saved, used essentially to isolate application code from
</p>
<p>
-<code> int lock_ex (int fd) </code> <br />
-Gets an exclusive advisory lock on <em>fd</em>. <em>fd</em> must point to
-a regular file, open for writing. Blocks until the lock can be obtained.
-Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
-</p>
-
-<p>
-<code> int lock_exnb (int fd) </code> <br />
-Gets an exclusive advisory lock on <em>fd</em>. <em>fd</em> must point to
-a regular file, open for writing.
-Returns 0 if it succeeds, or -1 (and sets errno) if it fails. If the lock
-is held and the function would block, it immediately returns with -1 EWOULDBLOCK.
-</p>
-
-<p>
-<code> int lock_sh (int fd) </code> <br />
-Gets a shared advisory lock on <em>fd</em>. <em>fd</em> must point to
-a regular file, open for reading. Blocks until the lock can be obtained.
-Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
-</p>
-
-<p>
-<code> int lock_shnb (int fd) </code> <br />
-Gets a shared advisory lock on <em>fd</em>. <em>fd</em> must point to
-a regular file, open for reading.
-Returns 0 if it succeeds, or -1 (and sets errno) if it fails. If the lock
-is held and the function would block, it immediately returns with -1 EWOULDBLOCK.
+<code> int fd_lock (int fd, int w, int nb) </code> <br />
+Gets an advisory lock on <em>fd</em>: shared if <em>w</em> is
+zero, exclusive otherwise. <em>fd</em> must point to
+a regular file, open for writing or reading depending on whether
+you want an exclusive lock or not. If <em>nb</em> is zero, the
+function blocks until the lock can be obtained; otherwise it
+returns 0 immediately. On success, the function returns 1 ; it
+returns 0 if it cannot take the lock, or -1 (and sets errno) if
+an error occurs.
</p>
<p>
-<code> int lock_un (int fd) </code> <br />
+<code> void fd_unlock (int fd) </code> <br />
Releases a previously held lock on <em>fd</em>.
-Returns 0 if it succeeds, or -1 (and sets errno) if it fails.
</p>
<p>
-<code> void lock_unx (int fd) </code> <br />
-Like <tt>lock_un</tt>, but without a return code and without
-modifying errno.
+<code> int fd_islocked (int fd) </code> <br />
+Returns 1 if a lock is currently held on fd, 0 otherwise.
+Returns -1 (and sets errno) if an error occurs.
</p>
<p>
diff --git a/doc/license.html b/doc/license.html
@@ -74,7 +74,7 @@ color, or different text font. </li>
<p>
<em>I am aware that the previous restrictions sound completely
ridiculous while the official skalibs documentation is incomplete.
-As of 2.9.4.0, I'm not going to enforce those restrictions, but if you're
+As of 2.10.0.0, I'm not going to enforce those restrictions, but if you're
going to provide documentation for skalibs, don't keep it to yourself,
please send it to me instead. :-) </em>
</p>
diff --git a/doc/upgrade.html b/doc/upgrade.html
@@ -16,7 +16,7 @@
<a href="//skarnet.org/">skarnet.org</a>
</p>
-<h2> in 2.9.4.0 </h2>
+<h2> in 2.10.0.0 </h2>
<ul>
<li> New <tt>openc_*</tt> functions, which are O_CLOEXEC versions of the
@@ -25,6 +25,8 @@
deleting a Unix domain socket. The <tt>ipc_bind_reuse()</tt> function now
uses it, so it won't unconditionally clobber sockets in the filesystem anymore. </li>
<li> Complete revamping of the pathexec functions, see <tt>exec.h</tt>. </li>
+ <li> Revamping of the locking functions, see
+<a href="libstddjb/djbunix.html>djbunix.h</a>. </li>
</ul>
<h2> in 2.9.3.0 </h2>
diff --git a/package/deps.mak b/package/deps.mak
@@ -19,7 +19,7 @@ src/include/skalibs/cdb.h: src/include/skalibs/gccattributes.h
src/include/skalibs/cdb_make.h: src/include/skalibs/allreadwrite.h src/include/skalibs/buffer.h src/include/skalibs/diuint32.h src/include/skalibs/genalloc.h
src/include/skalibs/datastruct.h: src/include/skalibs/avlnode.h src/include/skalibs/avltree.h src/include/skalibs/avltreen.h src/include/skalibs/bigkv.h src/include/skalibs/genqdyn.h src/include/skalibs/genset.h src/include/skalibs/gensetdyn.h
src/include/skalibs/djbtime.h: src/include/skalibs/tai.h src/include/skalibs/uint64.h
-src/include/skalibs/djbunix.h: src/include/skalibs/exec.h src/include/skalibs/gccattributes.h src/include/skalibs/stralloc.h
+src/include/skalibs/djbunix.h: src/include/skalibs/gccattributes.h src/include/skalibs/stralloc.h
src/include/skalibs/env.h: src/include/skalibs/gccattributes.h src/include/skalibs/stralloc.h
src/include/skalibs/envalloc.h: src/include/skalibs/genalloc.h
src/include/skalibs/environ.h: src/include/skalibs/posixplz.h
@@ -349,6 +349,8 @@ src/libstddjb/fd_close.o src/libstddjb/fd_close.lo: src/libstddjb/fd_close.c src
src/libstddjb/fd_copy.o src/libstddjb/fd_copy.lo: src/libstddjb/fd_copy.c src/include/skalibs/djbunix.h
src/libstddjb/fd_copy2.o src/libstddjb/fd_copy2.lo: src/libstddjb/fd_copy2.c src/include/skalibs/djbunix.h
src/libstddjb/fd_ensure_open.o src/libstddjb/fd_ensure_open.lo: src/libstddjb/fd_ensure_open.c src/include/skalibs/djbunix.h
+src/libstddjb/fd_islocked.o src/libstddjb/fd_islocked.lo: src/libstddjb/fd_islocked.c src/include/skalibs/djbunix.h
+src/libstddjb/fd_lock.o src/libstddjb/fd_lock.lo: src/libstddjb/fd_lock.c src/include/skalibs/djbunix.h src/include/skalibs/error.h
src/libstddjb/fd_move.o src/libstddjb/fd_move.lo: src/libstddjb/fd_move.c src/include/skalibs/djbunix.h
src/libstddjb/fd_move2.o src/libstddjb/fd_move2.lo: src/libstddjb/fd_move2.c src/include/skalibs/djbunix.h
src/libstddjb/fd_read.o src/libstddjb/fd_read.lo: src/libstddjb/fd_read.c src/include/skalibs/allreadwrite.h
@@ -357,6 +359,7 @@ src/libstddjb/fd_recv.o src/libstddjb/fd_recv.lo: src/libstddjb/fd_recv.c src/in
src/libstddjb/fd_send.o src/libstddjb/fd_send.lo: src/libstddjb/fd_send.c src/include/skalibs/allreadwrite.h
src/libstddjb/fd_shutdown.o src/libstddjb/fd_shutdown.lo: src/libstddjb/fd_shutdown.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h
src/libstddjb/fd_sync.o src/libstddjb/fd_sync.lo: src/libstddjb/fd_sync.c src/include/skalibs/djbunix.h
+src/libstddjb/fd_unlock.o src/libstddjb/fd_unlock.lo: src/libstddjb/fd_unlock.c src/include/skalibs/djbunix.h
src/libstddjb/fd_write.o src/libstddjb/fd_write.lo: src/libstddjb/fd_write.c src/include/skalibs/allreadwrite.h
src/libstddjb/fd_writev.o src/libstddjb/fd_writev.lo: src/libstddjb/fd_writev.c src/include/skalibs/allreadwrite.h
src/libstddjb/filecopy_suffix.o src/libstddjb/filecopy_suffix.lo: src/libstddjb/filecopy_suffix.c src/include/skalibs/djbunix.h
@@ -448,12 +451,6 @@ src/libstddjb/localtmn_fmt.o src/libstddjb/localtmn_fmt.lo: src/libstddjb/localt
src/libstddjb/localtmn_from_sysclock.o src/libstddjb/localtmn_from_sysclock.lo: src/libstddjb/localtmn_from_sysclock.c src/include/skalibs/djbtime.h
src/libstddjb/localtmn_from_tain.o src/libstddjb/localtmn_from_tain.lo: src/libstddjb/localtmn_from_tain.c src/include/skalibs/djbtime.h
src/libstddjb/localtmn_scan.o src/libstddjb/localtmn_scan.lo: src/libstddjb/localtmn_scan.c src/include/skalibs/djbtime.h src/include/skalibs/uint32.h
-src/libstddjb/lock_ex.o src/libstddjb/lock_ex.lo: src/libstddjb/lock_ex.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
-src/libstddjb/lock_exnb.o src/libstddjb/lock_exnb.lo: src/libstddjb/lock_exnb.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
-src/libstddjb/lock_sh.o src/libstddjb/lock_sh.lo: src/libstddjb/lock_sh.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
-src/libstddjb/lock_shnb.o src/libstddjb/lock_shnb.lo: src/libstddjb/lock_shnb.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
-src/libstddjb/lock_un.o src/libstddjb/lock_un.lo: src/libstddjb/lock_un.c src/include/skalibs/djbunix.h src/include/skalibs/nonposix.h src/include/skalibs/sysdeps.h
-src/libstddjb/lock_unx.o src/libstddjb/lock_unx.lo: src/libstddjb/lock_unx.c src/include/skalibs/djbunix.h
src/libstddjb/lolprintf.o src/libstddjb/lolprintf.lo: src/libstddjb/lolprintf.c src/include/skalibs/buffer.h src/include/skalibs/lolstdio.h
src/libstddjb/ltm64_from_localtm.o src/libstddjb/ltm64_from_localtm.lo: src/libstddjb/ltm64_from_localtm.c src/include/skalibs/djbtime.h src/include/skalibs/tai.h
src/libstddjb/ltm64_from_sysclock.o src/libstddjb/ltm64_from_sysclock.lo: src/libstddjb/ltm64_from_sysclock.c src/include/skalibs/config.h src/include/skalibs/djbtime.h src/include/skalibs/tai.h
diff --git a/package/info b/package/info
@@ -1,4 +1,4 @@
package=skalibs
-version=2.9.4.0
+version=2.10.0.0
category=prog
package_macro_name=SKALIBS
diff --git a/src/include/skalibs/djbunix.h b/src/include/skalibs/djbunix.h
@@ -9,7 +9,6 @@
#include <skalibs/gccattributes.h>
#include <skalibs/stralloc.h>
-#include <skalibs/exec.h> /* compat */
#define DJBUNIX_FLAG_NB 0x01U
#define DJBUNIX_FLAG_COE 0x02U
@@ -35,12 +34,11 @@ extern size_t fd_catn (int, int, size_t) ;
extern int fd_ensure_open (int, int) ;
#define fd_sanitize() (fd_ensure_open(0, 0) && fd_ensure_open(1, 1) && fd_ensure_open(2, 1))
extern void fd_shutdown (int, int) ;
-extern int lock_ex (int) ;
-extern int lock_exnb (int) ;
-extern int lock_sh (int) ;
-extern int lock_shnb (int) ;
-extern int lock_un (int) ;
-extern void lock_unx (int) ;
+
+extern int fd_lock (int, int, int) ;
+extern void fd_unlock (int) ;
+extern int fd_islocked (int) ;
+
extern int open2 (char const *, unsigned int) ;
extern int open3 (char const *, unsigned int, unsigned int) ;
extern int open_read (char const *) ;
diff --git a/src/include/skalibs/exec.h b/src/include/skalibs/exec.h
@@ -139,6 +139,7 @@ extern void xmexec0_af (char const *, char const *const *, char const *const *,
/* Compatibility */
+#if 0
#define pathexec_run(file, argv, envp) exec_ae(file, argv, envp)
#define pathexec0_run(argv, envp) exec0_e(argv, envp)
#define xpathexec_run(file, argv, envp) xexec_ae(file, argv, envp)
@@ -156,5 +157,6 @@ extern void xmexec0_af (char const *, char const *const *, char const *const *,
#define pathexec_r(argv, envp, envlen, modif, modiflen) mexec_fm(argv, envp, envlen, modif, modiflen)
#define xpathexec_r_name(file, argv, envp, envlen, modif, modiflen) xmexec_afm(file, argv, envp, envlen, modif, modiflen)
#define xpathexec_r(argv, envp, envlen, modif, modiflen) xmexec_fm(argv, envp, envlen, modif, modiflen)
+#endif
#endif
diff --git a/src/libstddjb/fd_islocked.c b/src/libstddjb/fd_islocked.c
@@ -0,0 +1,17 @@
+/* ISC license. */
+
+#include <fcntl.h>
+
+#include <skalibs/djbunix.h>
+
+int fd_islocked (int fd)
+{
+ struct flock fl =
+ {
+ .l_type = F_RDLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0
+ } ;
+ return fcntl(fd, F_GETLK, &fl) < 0 ? -1 : fl.l_type != F_UNLCK ;
+}
diff --git a/src/libstddjb/fd_lock.c b/src/libstddjb/fd_lock.c
@@ -0,0 +1,25 @@
+/* ISC license. */
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <skalibs/error.h>
+#include <skalibs/djbunix.h>
+
+int fd_lock (int fd, int w, int nb)
+{
+ struct flock fl =
+ {
+ .l_type = w ? F_WRLCK : F_RDLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0
+ } ;
+ int e = errno ;
+ int r ;
+ do r = fcntl(fd, nb ? F_SETLK : F_SETLKW, &fl) ;
+ while (r < 0 && errno == EINTR) ;
+ return r >= 0 ? 1 :
+ errno == EACCES || error_isagain(errno) ? (errno = e, 0) :
+ -1 ;
+}
diff --git a/src/libstddjb/fd_unlock.c b/src/libstddjb/fd_unlock.c
@@ -0,0 +1,20 @@
+/* ISC license. */
+
+#include <fcntl.h>
+#include <errno.h>
+
+#include <skalibs/djbunix.h>
+
+void fd_unlock (int fd)
+{
+ struct flock fl =
+ {
+ .l_type = F_UNLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 0
+ } ;
+ int e = errno ;
+ fcntl(fd, F_SETLK, &fl) ;
+ errno = e ;
+}
diff --git a/src/libstddjb/ipc_bind_reuse_lock.c b/src/libstddjb/ipc_bind_reuse_lock.c
@@ -4,6 +4,7 @@
#include <string.h>
#include <unistd.h>
+#include <errno.h>
#include <sys/socket.h>
#include <skalibs/djbunix.h>
@@ -14,12 +15,15 @@ int ipc_bind_reuse_lock (int s, char const *p, int *fdlock)
unsigned int opt = 1 ;
size_t len = strlen(p) ;
int fd ;
+ int r ;
char lockname[len + 6] ;
memcpy(lockname, p, len) ;
memcpy(lockname + len, ".lock", 6) ;
fd = openc_create(lockname) ;
if (fd < 0) return -1 ;
- if (lock_exnb(fd) < 0) return -1 ;
+ r = fd_lock(fd, 1, 1) ;
+ if (r < 0) return -1 ;
+ if (!r) return (errno = EBUSY, -1) ;
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt) ;
unlink(p) ;
if (ipc_bind(s, p) < 0) return -1 ;
diff --git a/src/libstddjb/lock_ex.c b/src/libstddjb/lock_ex.c
@@ -1,34 +0,0 @@
-/* ISC license. */
-
-#include <skalibs/sysdeps.h>
-
-#ifdef SKALIBS_HASFLOCK
-
-#include <skalibs/nonposix.h>
-#include <errno.h>
-#include <sys/file.h>
-#include <skalibs/djbunix.h>
-
-int lock_ex (int fd)
-{
- int r ;
- do r = flock(fd, LOCK_EX) ;
- while ((r == -1) && (errno == EINTR)) ;
- return r ;
-}
-
-#else
-
-#include <unistd.h>
-#include <errno.h>
-#include <skalibs/djbunix.h>
-
-int lock_ex (int fd)
-{
- int r ;
- do r = lockf(fd, F_LOCK, 0) ;
- while ((r == -1) && (errno == EINTR)) ;
- return r ;
-}
-
-#endif
diff --git a/src/libstddjb/lock_exnb.c b/src/libstddjb/lock_exnb.c
@@ -1,35 +0,0 @@
-/* ISC license. */
-
-#include <skalibs/sysdeps.h>
-
-#ifdef SKALIBS_HASFLOCK
-
-#include <skalibs/nonposix.h>
-#include <errno.h>
-#include <sys/file.h>
-#include <skalibs/djbunix.h>
-
-int lock_exnb (int fd)
-{
- int r ;
- do r = flock(fd, LOCK_EX | LOCK_NB) ;
- while ((r == -1) && (errno == EINTR)) ;
- return r ;
-}
-
-#else
-
-#include <unistd.h>
-#include <errno.h>
-#include <skalibs/djbunix.h>
-
-int lock_exnb (int fd)
-{
- int r ;
- do r = lockf(fd, F_TLOCK, 0) ;
- while ((r == -1) && (errno == EINTR)) ;
- if ((r == -1) && (errno == EACCES)) errno = EAGAIN ;
- return r ;
-}
-
-#endif
diff --git a/src/libstddjb/lock_sh.c b/src/libstddjb/lock_sh.c
@@ -1,34 +0,0 @@
-/* ISC license. */
-
-#include <skalibs/sysdeps.h>
-
-#ifdef SKALIBS_HASFLOCK
-
-#include <skalibs/nonposix.h>
-#include <errno.h>
-#include <sys/file.h>
-#include <skalibs/djbunix.h>
-
-int lock_sh (int fd)
-{
- int r ;
- do r = flock(fd, LOCK_SH) ;
- while ((r == -1) && (errno == EINTR)) ;
- return r ;
-}
-
-#else
-
-#include <unistd.h>
-#include <errno.h>
-#include <skalibs/djbunix.h>
-
-int lock_sh (int fd)
-{
- int r ;
- do r = lockf(fd, F_LOCK, 0) ;
- while ((r == -1) && (errno == EINTR)) ;
- return r ;
-}
-
-#endif
diff --git a/src/libstddjb/lock_shnb.c b/src/libstddjb/lock_shnb.c
@@ -1,35 +0,0 @@
-/* ISC license. */
-
-#include <skalibs/sysdeps.h>
-
-#ifdef SKALIBS_HASFLOCK
-
-#include <skalibs/nonposix.h>
-#include <errno.h>
-#include <sys/file.h>
-#include <skalibs/djbunix.h>
-
-int lock_shnb (int fd)
-{
- int r ;
- do r = flock(fd, LOCK_SH | LOCK_NB) ;
- while ((r == -1) && (errno == EINTR)) ;
- return r ;
-}
-
-#else
-
-#include <unistd.h>
-#include <errno.h>
-#include <skalibs/djbunix.h>
-
-int lock_shnb (int fd)
-{
- int r ;
- do r = lockf(fd, F_TLOCK, 0) ;
- while ((r == -1) && (errno == EINTR)) ;
- if ((r == -1) && (errno == EACCES)) errno = EAGAIN ;
- return r ;
-}
-
-#endif
diff --git a/src/libstddjb/lock_un.c b/src/libstddjb/lock_un.c
@@ -1,34 +0,0 @@
-/* ISC license. */
-
-#include <skalibs/sysdeps.h>
-
-#ifdef SKALIBS_HASFLOCK
-
-#include <skalibs/nonposix.h>
-#include <errno.h>
-#include <sys/file.h>
-#include <skalibs/djbunix.h>
-
-int lock_un (int fd)
-{
- int r ;
- do r = flock(fd, LOCK_UN) ;
- while ((r == -1) && (errno == EINTR)) ;
- return r ;
-}
-
-#else
-
-#include <unistd.h>
-#include <errno.h>
-#include <skalibs/djbunix.h>
-
-int lock_un (int fd)
-{
- int r ;
- do r = lockf(fd, F_ULOCK, 0) ;
- while ((r == -1) && (errno == EINTR)) ;
- return r ;
-}
-
-#endif
diff --git a/src/libstddjb/lock_unx.c b/src/libstddjb/lock_unx.c
@@ -1,11 +0,0 @@
-/* ISC license. */
-
-#include <errno.h>
-#include <skalibs/djbunix.h>
-
-void lock_unx (int fd)
-{
- int e = errno ;
- lock_un(fd) ;
- errno = e ;
-}