$ 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


Reply via email to