Hey,
This patch changes some of the timers in tmux to the
monotonic clock.
None of these are user-facing. Changing them eliminates
the clock jump edge cases with little additional complexity.
To make the changes as unobtrusive as possible I added
a new module, time.c, which contains monotonic analogues
for time(3) and gettimeofday(2).
The interval timed in grid.c resembles a performance
measurement, so getrusage(2) or the CLOCK_PROCESS_CPUTIME_ID
clock might be more appropriate.
The timers unchanged by this patch that aren't handled by
libevent (e.g. activity timestamps) are more complicated
because they are user-facing and serve multiple purposes:
a mix of timestamps, heuristics, and interval measurements.
So those merit a separate discussion and might not be worth
the added complexity.
Thoughts and feedback?
--
Scott Cheloha
Index: usr.bin/tmux/Makefile
===================================================================
RCS file: /cvs/src/usr.bin/tmux/Makefile,v
retrieving revision 1.89
diff -u -p -r1.89 Makefile
--- usr.bin/tmux/Makefile 12 Jul 2017 09:24:17 -0000 1.89
+++ usr.bin/tmux/Makefile 5 Dec 2017 14:24:39 -0000
@@ -104,6 +104,7 @@ SRCS= alerts.c \
session.c \
status.c \
style.c \
+ time.c \
tmux.c \
tty-acs.c \
tty-keys.c \
Index: usr.bin/tmux/format.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/format.c,v
retrieving revision 1.150
diff -u -p -r1.150 format.c
--- usr.bin/tmux/format.c 2 Nov 2017 18:52:05 -0000 1.150
+++ usr.bin/tmux/format.c 5 Dec 2017 14:24:39 -0000
@@ -192,7 +192,7 @@ format_job_update(struct job *job)
{
struct format_job *fj = job->data;
char *line;
- time_t t;
+ time_t now;
if ((line = evbuffer_readline(job->event->input)) == NULL)
return;
@@ -203,11 +203,11 @@ format_job_update(struct job *job)
log_debug("%s: %p %s: %s", __func__, fj, fj->cmd, fj->out);
- t = time(NULL);
- if (fj->status && fj->last != t) {
+ now = monotime(NULL);
+ if (fj->status && fj->last != now) {
if (fj->client != NULL)
server_status_client(fj->client);
- fj->last = t;
+ fj->last = now;
}
}
@@ -252,7 +252,7 @@ format_job_get(struct format_tree *ft, c
{
struct format_job_tree *jobs;
struct format_job fj0, *fj;
- time_t t;
+ time_t now;
char *expanded;
int force;
@@ -287,15 +287,15 @@ format_job_get(struct format_tree *ft, c
} else
force = (ft->flags & FORMAT_FORCE);
- t = time(NULL);
- if (fj->job == NULL && (force || fj->last != t)) {
+ now = monotime(NULL);
+ if (fj->job == NULL && (force || fj->last != now)) {
fj->job = job_run(expanded, NULL, NULL, format_job_update,
format_job_complete, NULL, fj);
if (fj->job == NULL) {
free(fj->out);
xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd);
}
- fj->last = t;
+ fj->last = now;
fj->updated = 0;
}
@@ -313,7 +313,7 @@ format_job_tidy(struct format_job_tree *
struct format_job *fj, *fj1;
time_t now;
- now = time(NULL);
+ now = monotime(NULL);
RB_FOREACH_SAFE(fj, format_job_tree, jobs, fj1) {
if (!force && (fj->last > now || now - fj->last < 3600))
continue;
Index: usr.bin/tmux/grid.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/grid.c,v
retrieving revision 1.79
diff -u -p -r1.79 grid.c
--- usr.bin/tmux/grid.c 15 Nov 2017 19:21:24 -0000 1.79
+++ usr.bin/tmux/grid.c 5 Dec 2017 14:24:39 -0000
@@ -1128,7 +1128,7 @@ grid_reflow(struct grid *gd, u_int sx, u
u_int yy, cy, width, i, at, first;
struct timeval start, tv;
- gettimeofday(&start, NULL);
+ getmonotime(&start);
log_debug("%s: %u lines, new width %u", __func__, gd->hsize + gd->sy,
sx);
@@ -1201,7 +1201,7 @@ grid_reflow(struct grid *gd, u_int sx, u
else
*cursor = cy - gd->hsize;
- gettimeofday(&tv, NULL);
+ getmonotime(&tv);
timersub(&tv, &start, &tv);
log_debug("%s: now %u lines (in %llu.%06u seconds)", __func__,
gd->hsize + gd->sy, (unsigned long long)tv.tv_sec,
Index: usr.bin/tmux/names.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/names.c,v
retrieving revision 1.41
diff -u -p -r1.41 names.c
--- usr.bin/tmux/names.c 21 Jul 2017 12:58:02 -0000 1.41
+++ usr.bin/tmux/names.c 5 Dec 2017 14:24:39 -0000
@@ -69,7 +69,7 @@ check_window_name(struct window *w)
}
log_debug("@%u active pane changed", w->id);
- gettimeofday(&tv, NULL);
+ getmonotime(&tv);
left = name_time_expired(w, &tv);
if (left != 0) {
if (!event_initialized(&w->name_event))
Index: usr.bin/tmux/time.c
===================================================================
RCS file: usr.bin/tmux/time.c
diff -N usr.bin/tmux/time.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ usr.bin/tmux/time.c 5 Dec 2017 14:24:39 -0000
@@ -0,0 +1,30 @@
+/* $OpenBSD$ */
+
+#include <sys/time.h>
+
+#include <time.h>
+
+#include "tmux.h"
+
+int
+getmonotime(struct timeval *tv)
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+ return (-1);
+ TIMESPEC_TO_TIMEVAL(tv, &ts);
+ return (0);
+}
+
+time_t
+monotime(time_t *t)
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+ return (-1);
+ if (t)
+ *t = ts.tv_sec;
+ return (ts.tv_sec);
+}
Index: usr.bin/tmux/tmux.h
===================================================================
RCS file: /cvs/src/usr.bin/tmux/tmux.h,v
retrieving revision 1.814
diff -u -p -r1.814 tmux.h
--- usr.bin/tmux/tmux.h 15 Nov 2017 19:59:27 -0000 1.814
+++ usr.bin/tmux/tmux.h 5 Dec 2017 14:24:39 -0000
@@ -2391,4 +2391,8 @@ void style_apply_update(struct grid_ce
int style_equal(const struct grid_cell *,
const struct grid_cell *);
+/* time.c */
+int getmonotime(struct timeval *);
+time_t monotime(time_t *);
+
#endif /* TMUX_H */
Index: usr.bin/tmux/window.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/window.c,v
retrieving revision 1.207
diff -u -p -r1.207 window.c
--- usr.bin/tmux/window.c 9 Nov 2017 23:02:13 -0000 1.207
+++ usr.bin/tmux/window.c 5 Dec 2017 14:24:39 -0000
@@ -1202,7 +1202,7 @@ window_pane_mode_timer(__unused int fd,
log_debug("%%%u in mode: last=%ld", wp->id, (long)wp->modelast);
- if (wp->modelast < time(NULL) - WINDOW_MODE_TIMEOUT) {
+ if (wp->modelast < monotime(NULL) - WINDOW_MODE_TIMEOUT) {
if (ioctl(wp->fd, FIONREAD, &n) == -1 || n > 0)
window_pane_reset_mode(wp);
}
@@ -1219,7 +1219,7 @@ window_pane_set_mode(struct window_pane
return (1);
wp->mode = mode;
- wp->modelast = time(NULL);
+ wp->modelast = monotime(NULL);
evtimer_set(&wp->modetimer, window_pane_mode_timer, wp);
evtimer_add(&wp->modetimer, &tv);
@@ -1261,7 +1261,7 @@ window_pane_key(struct window_pane *wp,
return;
if (wp->mode != NULL) {
- wp->modelast = time(NULL);
+ wp->modelast = monotime(NULL);
if (wp->mode->key != NULL)
wp->mode->key(wp, c, s, (key & ~KEYC_XTERM), m);
return;