$ time mksh -c 'while ((SECONDS < 1)); do :; done'
mksh -c 'while ((SECONDS < 1)); do :; done' 0.46s user 0.00s system 99% cpu
0.465 total
That can take in between 0 and 1 seconds. Or in other words,
$SECONDS becomes 1 in between 0 and 1 second after the shell was
started.
The reason seems to be because the shell records the value
returned by gettimeofday() upon start-up and upon expanding
$SECONDS but only consideres the "seconds" fields when
substracting the two times, ignoring the microsecond field.
So, if mksh is started at 10:00:00.999, then $SECONDS will
become 1 only a milisecond after startup while if it's started
at 10:00:01.000, $SECONDS will become 1 a full second later.
IMO, it would be better if mksh also used the tv_usec part in
the substraction so that $SECONDS be incremented exactly one
second after start-up like ksh93 does.
bash and zsh behave like mksh (I'll raise the issue there as
well).
With zsh (like in ksh93), one can do "typeset -F SECONDS" to
make $SECONDS floating point, which can be used as a work around
of the "issue".
diff --git a/var.c b/var.c
index 1e285f2..81371bd 100644
--- a/var.c
+++ b/var.c
@@ -1175,7 +1175,7 @@ unspecial(const char *name)
ktdelete(tp);
}
-static time_t seconds; /* time SECONDS last set */
+static struct timeval seconds; /* time SECONDS last set */
static mksh_uari_t user_lineno; /* what user set $LINENO to */
static void
@@ -1241,7 +1241,8 @@ getspec(struct tbl *vp)
*/
if (vp->flag & ISSET) {
mksh_TIME(tv);
- num.i = tv.tv_sec - seconds;
+ num.i = tv.tv_sec - seconds.tv_sec;
+ if (tv.tv_usec < seconds.tv_usec) num.i--;
} else
return;
break;
@@ -1358,7 +1359,8 @@ setspec(struct tbl *vp)
struct timeval tv;
mksh_TIME(tv);
- seconds = tv.tv_sec - num.i;
+ seconds.tv_sec = tv.tv_sec - num.i;
+ seconds.tv_usec = tv.tv_usec;
}
break;
case V_TMOUT:
--
Stephane