From 25c9b61a6663f90bfb22fa73c1a7aa4fb9dee4ae Mon Sep 17 00:00:00 2001 From: Cedric Ware Date: Mon, 20 Apr 2020 12:10:01 -0500 Subject: 45708: zsh/system: Enable sub-second timeout in zsystem flock --- Src/Modules/system.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 5 deletions(-) (limited to 'Src/Modules/system.c') diff --git a/Src/Modules/system.c b/Src/Modules/system.c index fb3d80773..972aa0767 100644 --- a/Src/Modules/system.c +++ b/Src/Modules/system.c @@ -29,6 +29,7 @@ #include "system.mdh" #include "system.pro" +#include #ifdef HAVE_POLL_H # include @@ -531,7 +532,9 @@ static int bin_zsystem_flock(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { int cloexec = 1, unlock = 0, readlock = 0; - zlong timeout = -1; + double timeout = -1; + long timeout_interval = 1e6; + mnumber timeout_param; char *fdvar = NULL; #ifdef HAVE_FCNTL_H struct flock lck; @@ -583,7 +586,51 @@ bin_zsystem_flock(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) } else { optarg = *args++; } - timeout = mathevali(optarg); + timeout_param = matheval(optarg); + timeout = (timeout_param.type & MN_FLOAT) ? + timeout_param.u.d : (double)timeout_param.u.l; + + /* + * timeout must not overflow time_t, but little is known + * about this type's limits. Conservatively limit to 2^30-1 + * (34 years). Then it can only overflow if time_t is only + * a 32-bit int and CLOCK_MONOTONIC is not supported, in which + * case there is a Y2038 problem anyway. + */ + if (timeout < 1e-6 || timeout > 1073741823.) { + zwarnnam(nam, "flock: invalid timeout value: '%s'", + optarg); + return 1; + } + break; + + case 'i': + /* retry interval in seconds */ + if (optptr[1]) { + optarg = optptr + 1; + optptr += strlen(optarg) - 1; + } else if (!*args) { + zwarnnam(nam, + "flock: option %c requires " + "a numeric retry interval", + 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; + } + timeout_param.u.d *= 1e6; + if (timeout_param.u.d < 1 + || timeout_param.u.d > 0.999 * LONG_MAX) { + zwarnnam(nam, "flock: invalid interval value: '%s'", + optarg); + return 1; + } + timeout_interval = (long)timeout_param.u.d; break; case 'u': @@ -647,7 +694,24 @@ bin_zsystem_flock(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) lck.l_len = 0; /* lock the whole file */ if (timeout > 0) { - time_t end = time(NULL) + (time_t)timeout; + /* + * Get current time, calculate timeout time. + * No need to check for overflow, already checked above. + */ + struct timespec now, end; + double timeout_s; + long remaining_us; + zgettime_monotonic_if_available(&now); + end.tv_sec = now.tv_sec; + end.tv_nsec = now.tv_nsec; + end.tv_nsec += modf(timeout, &timeout_s) * 1000000000L; + end.tv_sec += timeout_s; + if (end.tv_nsec >= 1000000000L) { + end.tv_nsec -= 1000000000L; + end.tv_sec += 1; + } + + /* Try acquiring lock, loop until timeout. */ while (fcntl(flock_fd, F_SETLK, &lck) < 0) { if (errflag) { zclose(flock_fd); @@ -658,11 +722,16 @@ bin_zsystem_flock(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) zwarnnam(nam, "failed to lock file %s: %e", args[0], errno); return 1; } - if (time(NULL) >= end) { + zgettime_monotonic_if_available(&now); + remaining_us = timespec_diff_us(&now, &end); + if (remaining_us <= 0) { zclose(flock_fd); return 2; } - sleep(1); + if (remaining_us <= timeout_interval) { + timeout_interval = remaining_us; + } + zsleep(timeout_interval); } } else { while (fcntl(flock_fd, timeout == 0 ? F_SETLK : F_SETLKW, &lck) < 0) { -- cgit v1.2.3 From 4d7aa71d8ed64827df4d8efd993abffcbc0fc075 Mon Sep 17 00:00:00 2001 From: Cedric Ware Date: Sat, 11 Jul 2020 00:14:58 -0500 Subject: 46152: zsh/system: Re-allow '0' timeout in zsystem flock --- ChangeLog | 5 +++++ Src/Modules/system.c | 6 +++--- Test/V14system.ztst | 21 ++++++++++----------- 3 files changed, 18 insertions(+), 14 deletions(-) (limited to 'Src/Modules/system.c') diff --git a/ChangeLog b/ChangeLog index d8da32500..a05703cbb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2020-07-11 dana + + * Cedric Ware: 46152: Src/Modules/system.c, Test/V14system.ztst: + Re-allow '0' timeout in zsystem flock + 2020-07-09 Jun-ichi Takimoto * 46215 (w/ minor tweak): Test/E01options.ztst: make the test diff --git a/Src/Modules/system.c b/Src/Modules/system.c index 972aa0767..ecd4e2546 100644 --- a/Src/Modules/system.c +++ b/Src/Modules/system.c @@ -597,7 +597,7 @@ bin_zsystem_flock(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) * a 32-bit int and CLOCK_MONOTONIC is not supported, in which * case there is a Y2038 problem anyway. */ - if (timeout < 1e-6 || timeout > 1073741823.) { + if (timeout > 1073741823.) { zwarnnam(nam, "flock: invalid timeout value: '%s'", optarg); return 1; @@ -623,7 +623,7 @@ bin_zsystem_flock(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) timeout_param.type = MN_FLOAT; timeout_param.u.d = (double)timeout_param.u.l; } - timeout_param.u.d *= 1e6; + timeout_param.u.d = ceil(timeout_param.u.d * 1e6); if (timeout_param.u.d < 1 || timeout_param.u.d > 0.999 * LONG_MAX) { zwarnnam(nam, "flock: invalid interval value: '%s'", @@ -704,7 +704,7 @@ bin_zsystem_flock(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) zgettime_monotonic_if_available(&now); end.tv_sec = now.tv_sec; end.tv_nsec = now.tv_nsec; - end.tv_nsec += modf(timeout, &timeout_s) * 1000000000L; + end.tv_nsec += ceil(modf(timeout, &timeout_s) * 1000000000L); end.tv_sec += timeout_s; if (end.tv_nsec >= 1000000000L) { end.tv_nsec -= 1000000000L; diff --git a/Test/V14system.ztst b/Test/V14system.ztst index b8af96cda..100daab08 100644 --- a/Test/V14system.ztst +++ b/Test/V14system.ztst @@ -13,27 +13,26 @@ %test ( - zsystem flock -t 0.1 -i 0.000001 $tst_dir/file + zsystem flock -t 0 -i 0.000001 $tst_dir/file && + zsystem flock -t 0.1 -i 0.000001 $tst_dir/file && + zsystem flock -t 0.1 -i 0.0000001 $tst_dir/file && + zsystem flock -t 1 -i 0.000001 $tst_dir/file ) 0:zsystem flock valid time arguments ( - zsystem flock -t -1 $tst_dir/file || - zsystem flock -t 0.49e-6 $tst_dir/file || zsystem flock -t 1073741824 $tst_dir/file || zsystem flock -t 1e100 $tst_dir/file || zsystem flock -i -1 $tst_dir/file || - zsystem flock -i 0.49e-6 $tst_dir/file || + zsystem flock -i 0 $tst_dir/file || zsystem flock -i 1e100 $tst_dir/file ) 1:zsystem flock invalid time arguments -?(eval):zsystem:2: flock: invalid timeout value: '-1' -?(eval):zsystem:3: flock: invalid timeout value: '0.49e-6' -?(eval):zsystem:4: flock: invalid timeout value: '1073741824' -?(eval):zsystem:5: flock: invalid timeout value: '1e100' -?(eval):zsystem:6: flock: invalid interval value: '-1' -?(eval):zsystem:7: flock: invalid interval value: '0.49e-6' -?(eval):zsystem:8: flock: invalid interval value: '1e100' +?(eval):zsystem:2: flock: invalid timeout value: '1073741824' +?(eval):zsystem:3: flock: invalid timeout value: '1e100' +?(eval):zsystem:4: flock: invalid interval value: '-1' +?(eval):zsystem:5: flock: invalid interval value: '0' +?(eval):zsystem:6: flock: invalid interval value: '1e100' ( # Lock file for 1 second in the background. -- cgit v1.2.3 From 95749e9e652849215b5d09c5aaf8928056c41688 Mon Sep 17 00:00:00 2001 From: Matthew Martin Date: Thu, 31 Mar 2022 17:40:22 -0500 Subject: 49933: Add nonblock to sysopen --- ChangeLog | 3 +++ Doc/Zsh/mod_system.yo | 3 +++ Src/Modules/system.c | 5 ++++- 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'Src/Modules/system.c') diff --git a/ChangeLog b/ChangeLog index 7e97c79f0..a4f74a581 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2022-03-31 Matthew Martin + * 49933: Doc/Zsh/mod_system.yo, Src/Modules/system.c: Add + nonblock to sysopen. + * 49932: Completion/Zsh/Context/_brace_parameter: Update _brace_parameter # description. diff --git a/Doc/Zsh/mod_system.yo b/Doc/Zsh/mod_system.yo index 399b6fe03..884c3e753 100644 --- a/Doc/Zsh/mod_system.yo +++ b/Doc/Zsh/mod_system.yo @@ -62,6 +62,9 @@ suppress updating of the file atime item(tt(nofollow))( fail if var(file) is a symbolic link ) +item(tt(nonblock))( +the file is opened in nonblocking mode +) item(tt(sync))( request that writes wait until data has been physically written ) diff --git a/Src/Modules/system.c b/Src/Modules/system.c index ecd4e2546..71745548f 100644 --- a/Src/Modules/system.c +++ b/Src/Modules/system.c @@ -280,7 +280,7 @@ bin_syswrite(char *nam, char **args, Options ops, UNUSED(int func)) } -static struct { char *name; int oflag; } openopts[] = { +static struct { const char *name; int oflag; } openopts[] = { #ifdef O_CLOEXEC { "cloexec", O_CLOEXEC }, #else @@ -296,6 +296,9 @@ static struct { char *name; int oflag; } openopts[] = { #endif #ifdef O_NOATIME { "noatime", O_NOATIME }, +#endif +#ifdef O_NONBLOCK + { "nonblock", O_NONBLOCK}, #endif { "excl", O_EXCL | O_CREAT }, { "creat", O_CREAT }, -- cgit v1.2.3