aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Bennett <steveb@workware.net.au>2022-12-01 10:13:57 +1000
committerSteve Bennett <steveb@workware.net.au>2023-02-13 10:44:10 +1000
commita5ea6b096e9e9f9913ad860a847e3757580dd9e4 (patch)
treec3e317177151e3ad83e996ee198b28aff4765b03
parent4b26f0ec1fa38bcfc8b2bd500a9bef10372bb140 (diff)
downloadjimtcl-a5ea6b096e9e9f9913ad860a847e3757580dd9e4.zip
jimtcl-a5ea6b096e9e9f9913ad860a847e3757580dd9e4.tar.gz
jimtcl-a5ea6b096e9e9f9913ad860a847e3757580dd9e4.tar.bz2
clock millis, time: now use monotonic raw time if possible
Instead of using all time, these commands now use a monotonically increasing system timer so that they are not affected by time (e.g. ntp) adjustments. (But not on Windows since it doesn't work reliably) Fixes #240 Signed-off-by: Steve Bennett <steveb@workware.net.au>
-rw-r--r--auto.def5
-rw-r--r--jim-clock.c23
-rw-r--r--jim-eventloop.c34
-rw-r--r--jim.c46
-rw-r--r--jim.h10
5 files changed, 60 insertions, 58 deletions
diff --git a/auto.def b/auto.def
index 5d751f1..2cd63c5 100644
--- a/auto.def
+++ b/auto.def
@@ -251,7 +251,7 @@ cc-check-functions geteuid mkstemp isatty
cc-check-functions regcomp waitpid sigaction sys_signame sys_siglist isascii
cc-check-functions syslog opendir readlink sleep usleep pipe getaddrinfo utimes
cc-check-functions shutdown socketpair link symlink fsync dup umask
-cc-check-functions localtime gmtime strptime clock_gettime
+cc-check-functions localtime gmtime strptime
if {![cc-check-functions realpath]} {
cc-check-functions _fullpath
}
@@ -534,6 +534,9 @@ if {[have-feature windows]} {
set buildjimext 0
}
}
+} else {
+ # We don't trust any version of clock_gettime on windows
+ cc-check-functions clock_gettime
}
if {[have-feature termios.h]} {
lappend extra_objs jim-tty.o
diff --git a/jim-clock.c b/jim-clock.c
index 0ca3e7b..43d7f74 100644
--- a/jim-clock.c
+++ b/jim-clock.c
@@ -151,37 +151,32 @@ static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
static int clock_cmd_seconds(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
- Jim_SetResultInt(interp, time(NULL));
+ Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000000);
+ return JIM_OK;
+}
+static int clock_cmd_clicks(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW));
return JIM_OK;
}
static int clock_cmd_micros(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
- struct timeval tv;
-
- gettimeofday(&tv, NULL);
-
- Jim_SetResultInt(interp, (jim_wide) tv.tv_sec * 1000000 + tv.tv_usec);
-
+ Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME));
return JIM_OK;
}
static int clock_cmd_millis(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
- struct timeval tv;
-
- gettimeofday(&tv, NULL);
-
- Jim_SetResultInt(interp, (jim_wide) tv.tv_sec * 1000 + tv.tv_usec / 1000);
-
+ Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000);
return JIM_OK;
}
static const jim_subcmd_type clock_command_table[] = {
{ "clicks",
NULL,
- clock_cmd_micros,
+ clock_cmd_clicks,
0,
0,
/* Description: Returns the current time in 'clicks' */
diff --git a/jim-eventloop.c b/jim-eventloop.c
index 782d5dd..b9e0e97 100644
--- a/jim-eventloop.c
+++ b/jim-eventloop.c
@@ -237,32 +237,6 @@ void Jim_DeleteFileHandler(Jim_Interp *interp, int fd, int mask)
}
}
-/**
- * Returns the time of day in microseconds.
- * (the time base is not relevant here)
- */
-static jim_wide JimGetTimeUsec(Jim_EventLoop *eventLoop)
-{
- long long now;
- struct timeval tv;
-
-#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC_RAW)
- struct timespec ts;
-
- if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) == 0) {
- now = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
- }
- else
-#endif
- {
- gettimeofday(&tv, NULL);
-
- now = tv.tv_sec * 1000000LL + tv.tv_usec;
- }
-
- return now;
-}
-
jim_wide Jim_CreateTimeHandler(Jim_Interp *interp, jim_wide us,
Jim_TimeProc * proc, void *clientData, Jim_EventFinalizerProc * finalizerProc)
{
@@ -273,7 +247,7 @@ jim_wide Jim_CreateTimeHandler(Jim_Interp *interp, jim_wide us,
te = Jim_Alloc(sizeof(*te));
te->id = id;
te->initialus = us;
- te->when = JimGetTimeUsec(eventLoop) + us;
+ te->when = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) + us;
te->timeProc = proc;
te->finalizerProc = finalizerProc;
te->clientData = clientData;
@@ -374,7 +348,7 @@ jim_wide Jim_DeleteTimeHandler(Jim_Interp *interp, jim_wide id)
if (te) {
jim_wide remain;
- remain = te->when - JimGetTimeUsec(eventLoop);
+ remain = te->when - Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
remain = (remain < 0) ? 0 : remain;
Jim_FreeTimeHandler(interp, te);
@@ -432,7 +406,7 @@ int Jim_ProcessEvents(Jim_Interp *interp, int flags)
/* Calculate the time missing for the nearest
* timer to fire. */
- sleep_us = shortest->when - JimGetTimeUsec(eventLoop);
+ sleep_us = shortest->when - Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
if (sleep_us < 0) {
sleep_us = 0;
}
@@ -534,7 +508,7 @@ int Jim_ProcessEvents(Jim_Interp *interp, int flags)
te = te->next;
continue;
}
- if (JimGetTimeUsec(eventLoop) >= te->when) {
+ if (Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) >= te->when) {
id = te->id;
/* Remove from the list before executing */
Jim_RemoveTimeHandler(eventLoop, id);
diff --git a/jim.c b/jim.c
index fe1aa03..ac78fda 100644
--- a/jim.c
+++ b/jim.c
@@ -694,15 +694,35 @@ char *Jim_StrDupLen(const char *s, int l)
* Time related functions
* ---------------------------------------------------------------------------*/
-/* Returns current time in microseconds */
-static jim_wide JimClock(void)
+/* Returns current time in microseconds
+ * CLOCK_MONOTONIC (monotonic clock that is affected by time adjustments)
+ * CLOCK_MONOTONIC_RAW (monotonic clock that is not affected by time adjustments)
+ * CLOCK_REALTIME (wall time)
+ */
+jim_wide Jim_GetTimeUsec(unsigned type)
{
+ long long now;
struct timeval tv;
- gettimeofday(&tv, NULL);
- return (jim_wide) tv.tv_sec * 1000000 + tv.tv_usec;
+#if defined(HAVE_CLOCK_GETTIME)
+ struct timespec ts;
+
+ if (clock_gettime(type, &ts) == 0) {
+ now = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
+ }
+ else
+#endif
+ {
+ gettimeofday(&tv, NULL);
+
+ now = tv.tv_sec * 1000000LL + tv.tv_usec;
+ }
+
+ return now;
}
+
+
/* -----------------------------------------------------------------------------
* Hash Tables
* ---------------------------------------------------------------------------*/
@@ -5614,7 +5634,7 @@ int Jim_Collect(Jim_Interp *interp)
}
Jim_FreeHashTable(&marks);
interp->lastCollectId = interp->referenceNextId;
- interp->lastCollectTime = JimClock();
+ interp->lastCollectTime = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
return collected;
}
@@ -5627,7 +5647,7 @@ void Jim_CollectIfNeeded(Jim_Interp *interp)
jim_wide elapsedTime;
elapsedId = interp->referenceNextId - interp->lastCollectId;
- elapsedTime = JimClock() - interp->lastCollectTime;
+ elapsedTime = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - interp->lastCollectTime;
if (elapsedId > JIM_COLLECT_ID_PERIOD || elapsedTime > JIM_COLLECT_TIME_PERIOD) {
@@ -5658,7 +5678,7 @@ Jim_Interp *Jim_CreateInterp(void)
i->maxCallFrameDepth = JIM_MAX_CALLFRAME_DEPTH;
i->maxEvalDepth = JIM_MAX_EVAL_DEPTH;
- i->lastCollectTime = JimClock();
+ i->lastCollectTime = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
/* Note that we can create objects only after the
* interpreter liveList and freeList pointers are
@@ -14592,7 +14612,7 @@ static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
if (count < 0)
return JIM_OK;
i = count;
- start = JimClock();
+ start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
while (i-- > 0) {
int retval;
@@ -14601,7 +14621,7 @@ static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
return retval;
}
}
- elapsed = JimClock() - start;
+ elapsed = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
if (elapsed < count * 10) {
Jim_SetResult(interp, Jim_NewDoubleObj(interp, elapsed * 1.0 / count));
}
@@ -14637,11 +14657,11 @@ static int Jim_TimeRateCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const
}
/* Run until we exceed the time limit */
- start = JimClock();
+ start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
count = 0;
do {
int retval = Jim_EvalObj(interp, argv[1]);
- delta = JimClock() - start;
+ delta = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
if (retval != JIM_OK) {
return retval;
}
@@ -14649,11 +14669,11 @@ static int Jim_TimeRateCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const
} while (delta < us);
/* Now try to account for the loop and eval overhead */
- start = JimClock();
+ start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
n = 0;
do {
int retval = Jim_EvalObj(interp, interp->nullScriptObj);
- overhead = JimClock() - start;
+ overhead = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
if (retval != JIM_OK) {
return retval;
}
diff --git a/jim.h b/jim.h
index 07dfbeb..4162e5e 100644
--- a/jim.h
+++ b/jim.h
@@ -665,6 +665,16 @@ JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
JIM_EXPORT char **Jim_GetEnviron(void);
JIM_EXPORT void Jim_SetEnviron(char **env);
JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file);
+#ifndef CLOCK_REALTIME
+# define CLOCK_REALTIME 0
+#endif
+#ifndef CLOCK_MONOTONIC
+# define CLOCK_MONOTONIC 1
+#endif
+#ifndef CLOCK_MONOTONIC_RAW
+# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
+#endif
+JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);
/* evaluation */
JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);