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;

Reply via email to