From: Cedric Ware <cedric.ware__bml@normalesup.org>
To: zsh-workers@zsh.org
Subject: [PATCH] Enable sub-second timeout in zsystem flock
Date: Mon, 29 Jul 2019 22:35:21 +0200 [thread overview]
Message-ID: <20190729203521.upp5ku3bsr3hsnxq@phare.normalesup.org> (raw)
[-- Attachment #1: Type: text/plain, Size: 1762 bytes --]
Hello,
I'm interested in using the zsystem flock function in the zsh/system
module to lock files, with a timeout if the lock is already taken, but
currently the timeout value has a whole-second granularity and I'd like
to specify sub-second timeouts.
The attached patch (against zsh 5.7.1) modifies the bin_zsystem_flock()
function, allowing the -t option to take floating-point parameters, and
handles the timeout with microsecond granularity. It also adds option
-p to control the retrying period, which was previously hardcoded to
1 second.
I kept the same function's logic of periodically retrying to acquire
the lock in non-blocking mode. However, there may be a better way to
implement this timeout: set a timer such as setitimer(2) which sends
a SIGALRM on timeout, trap SIGALRM without SA_RESTART, then acquire the
lock in blocking mode; fcntl() will then block until SIGALRM is caught,
after which errno will be EINTR. Unfortunately, lacking knowledge of
zsh internals especially signal handling, I'm not confident that I can
reimplement it this way by myself.
The patch modifies Src/Modules/system.c and also Src/utils.c (to add
a function akin to time(NULL) but that returns microseconds, using
clock_gettime(CLOCK_MONOTONIC) if supported, or else gettimeofday()).
I did not modify the documentation yet, not being sure of people being
interested in this feature, nor of whether I should edit just the
Doc/Zsh/mod_system.yo file, or also Doc/{zshmodules.1,zsh.texi} or
others.
Also, I'm afraid that I only did minimal testing. I checked that
invoking zsystem flock with various values for -t and -p seems to do
what I intended. Is there a more rigorous test framework for this
kind of thing?
Thanks, best regards,
Cedric Ware.
[-- Attachment #2: zsh-5.7.1-flock-timeout.patch --]
[-- Type: text/x-diff, Size: 3047 bytes --]
diff -ur zsh-5.7.1.orig/Src/Modules/system.c zsh-5.7.1/Src/Modules/system.c
--- zsh-5.7.1.orig/Src/Modules/system.c 2018-12-14 08:50:17.000000000 +0100
+++ zsh-5.7.1/Src/Modules/system.c 2019-07-29 20:19:48.835060428 +0200
@@ -532,6 +532,8 @@
{
int cloexec = 1, unlock = 0, readlock = 0;
zlong timeout = -1;
+ long timeout_retry = 1e6;
+ mnumber timeout_param;
char *fdvar = NULL;
#ifdef HAVE_FCNTL_H
struct flock lck;
@@ -583,7 +585,35 @@
} else {
optarg = *args++;
}
- timeout = mathevali(optarg);
+ timeout_param = matheval(optarg);
+ if (!(timeout_param.type & MN_FLOAT)) {
+ timeout_param.type = MN_FLOAT;
+ timeout_param.u.d = (double)timeout_param.u.l;
+ }
+ timeout = (zlong)(timeout_param.u.d * 1e6);
+ break;
+
+ case 'p':
+ /* retry period in seconds */
+ if (optptr[1]) {
+ optarg = optptr + 1;
+ optptr += strlen(optarg) - 1;
+ } else if (!*args) {
+ zwarnnam(nam,
+ "flock: option %c requires a numeric retry period",
+ opt);
+ return 1;
+ } else {
+ optarg = *args++;
+ }
+ timeout_param = matheval(optarg);
+ if (!(timeout_param.type & MN_FLOAT)) {
+ timeout_param.type = MN_FLOAT;
+ timeout_param.u.d = (double)timeout_param.u.l;
+ }
+ zlong timeout_retry_tmp = timeout_param.u.d * 1e6;
+ timeout_retry = (timeout_retry_tmp > LONG_MAX) ?
+ LONG_MAX : timeout_retry_tmp;
break;
case 'u':
@@ -647,7 +677,7 @@
lck.l_len = 0; /* lock the whole file */
if (timeout > 0) {
- time_t end = time(NULL) + (time_t)timeout;
+ zlong end = time_clock_us() + timeout;
while (fcntl(flock_fd, F_SETLK, &lck) < 0) {
if (errflag) {
zclose(flock_fd);
@@ -658,11 +688,15 @@
zwarnnam(nam, "failed to lock file %s: %e", args[0], errno);
return 1;
}
- if (time(NULL) >= end) {
+ zlong now = time_clock_us();
+ if (now >= end) {
zclose(flock_fd);
return 2;
}
- sleep(1);
+ if (now + timeout_retry > end) {
+ timeout_retry = end - now;
+ }
+ zsleep(timeout_retry);
}
} else {
while (fcntl(flock_fd, timeout == 0 ? F_SETLK : F_SETLKW, &lck) < 0) {
diff -ur zsh-5.7.1.orig/Src/utils.c zsh-5.7.1/Src/utils.c
--- zsh-5.7.1.orig/Src/utils.c 2019-02-01 01:37:34.000000000 +0100
+++ zsh-5.7.1/Src/utils.c 2019-07-29 20:24:57.827073902 +0200
@@ -2724,6 +2724,26 @@
}
/*
+ * Return the current time in microseconds, using the system's
+ * monotonic clock if supported, the wall clock if not.
+ */
+
+/**/
+zlong
+time_clock_us(void)
+{
+#if defined(HAS_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ts.tv_sec * (zlong)1e6 + ts.tv_nsec / 1000;
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * (zlong)1e6 + tv.tv_usec;
+#endif
+}
+
+/*
* Sleep for the given number of microseconds --- must be within
* range of a long at the moment, but this is only used for
* limited internal purposes.
next reply other threads:[~2019-07-29 20:36 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-07-29 20:35 Cedric Ware [this message]
2019-07-29 22:25 ` Bart Schaefer
2020-01-04 18:47 ` Cedric Ware
2020-01-05 18:42 ` dana
2020-01-05 21:49 ` dana
2020-01-06 17:30 ` Cedric Ware
2020-01-06 17:36 ` Peter Stephenson
2020-01-07 3:48 ` dana
2020-01-11 15:41 ` Cedric Ware
2020-01-11 19:36 ` dana
2020-01-12 4:25 ` dana
2020-03-08 18:39 ` Cedric Ware
2020-03-12 18:46 ` dana
2020-03-12 19:13 ` dana
2020-03-14 21:04 ` Cedric Ware
2020-03-15 0:50 ` Daniel Shahaf
2020-03-15 1:04 ` dana
2020-03-15 16:03 ` Cedric Ware
2020-03-15 16:54 ` Daniel Shahaf
2020-03-15 17:35 ` Peter Stephenson
2020-03-15 18:36 ` Cedric Ware
2020-03-15 19:13 ` Daniel Shahaf
2020-04-13 21:34 ` Cedric Ware
2020-04-14 11:47 ` Daniel Shahaf
2020-04-14 20:21 ` Cedric Ware
2020-04-15 1:15 ` Daniel Shahaf
2020-04-15 2:05 ` dana
2020-04-16 4:24 ` Daniel Shahaf
2020-04-18 16:32 ` Cedric Ware
2020-04-20 17:28 ` dana
2020-04-20 22:17 ` Cedric Ware
2020-03-15 1:04 ` Daniel Shahaf
2020-03-13 14:26 ` dana
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190729203521.upp5ku3bsr3hsnxq@phare.normalesup.org \
--to=cedric.ware__bml@normalesup.org \
--cc=zsh-workers@zsh.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/zsh/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).