]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: ioloop: Perform calculcations for the detection of system clock glitches in...
authorStephan Bosch <stephan.bosch@dovecot.fi>
Sun, 16 Dec 2018 13:09:17 +0000 (14:09 +0100)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Tue, 10 Sep 2019 07:01:47 +0000 (10:01 +0300)
src/lib/ioloop-private.h
src/lib/ioloop.c

index dd39ad82d19f90c92e9a3e2e7f818fba22dac935..b5debb352342913e129a4f5a7458f636d01668b0 100644 (file)
@@ -25,7 +25,7 @@ struct ioloop {
        unsigned int max_fd_count;
 
        io_loop_time_moved_callback_t *time_moved_callback;
-       time_t next_max_time;
+       struct timeval next_max_time;
        uint64_t ioloop_wait_usecs;
        struct timeval wait_started;
 
index 78619ba0a73de9b7983576c193374fdd3ccf3ae8..6f1ab7b86ef6c2acc2bbf131741d15e4bd59ccec 100644 (file)
@@ -498,7 +498,8 @@ static int io_loop_get_wait_time(struct ioloop *ioloop, struct timeval *tv_r)
                   return -1 for poll/epoll infinity. */
                tv_r->tv_sec = INT_MAX / 1000;
                tv_r->tv_usec = 0;
-               ioloop->next_max_time = (1ULL << (TIME_T_MAX_BITS-1)) - 1;
+               ioloop->next_max_time.tv_sec = (1ULL << (TIME_T_MAX_BITS-1)) - 1;
+               ioloop->next_max_time.tv_usec = 0;
                return -1;
        }
 
@@ -512,7 +513,8 @@ static int io_loop_get_wait_time(struct ioloop *ioloop, struct timeval *tv_r)
                tv_now.tv_sec = 0;
                msecs = timeout_get_wait_time(timeout, tv_r, &tv_now);
        }
-       ioloop->next_max_time = (tv_now.tv_sec + msecs/1000) + 1;
+       ioloop->next_max_time = tv_now;
+       timeval_add_msecs(&ioloop->next_max_time, msecs);
 
        /* update ioloop_timeval - this is meant for io_loop_handle_timeouts()'s
           ioloop_wait_usecs calculation. normally after this we go to the
@@ -577,7 +579,7 @@ static void io_loop_timeouts_start_new(struct ioloop *ioloop)
        array_clear(&ioloop->timeouts_new);
 }
 
-static void io_loop_timeouts_update(struct ioloop *ioloop, long diff_secs)
+static void io_loop_timeouts_update(struct ioloop *ioloop, long long diff_usecs)
 {
        struct priorityq_item *const *items;
        unsigned int i, count;
@@ -587,16 +589,16 @@ static void io_loop_timeouts_update(struct ioloop *ioloop, long diff_secs)
        for (i = 0; i < count; i++) {
                struct timeout *to = (struct timeout *)items[i];
 
-               to->next_run.tv_sec += diff_secs;
+               timeval_add_usecs(&to->next_run, diff_usecs);
        }
 }
 
-static void io_loops_timeouts_update(long diff_secs)
+static void io_loops_timeouts_update(long long diff_usecs)
 {
        struct ioloop *ioloop;
 
        for (ioloop = current_ioloop; ioloop != NULL; ioloop = ioloop->prev)
-               io_loop_timeouts_update(ioloop, diff_secs);
+               io_loop_timeouts_update(ioloop, diff_usecs);
 }
 
 static void ioloop_add_wait_time(struct ioloop *ioloop)
@@ -620,31 +622,38 @@ static void ioloop_add_wait_time(struct ioloop *ioloop)
 static void io_loop_handle_timeouts_real(struct ioloop *ioloop)
 {
        struct priorityq_item *item;
-       struct timeval tv, tv_call;
+       struct timeval tv_old, tv, tv_call;
+       long long diff_usecs;
        data_stack_frame_t t_id;
 
+       tv_old = ioloop_timeval;
        if (gettimeofday(&ioloop_timeval, NULL) < 0)
                i_fatal("gettimeofday(): %m");
 
-       /* Don't bother comparing usecs. */
-       if (unlikely(ioloop_time > ioloop_timeval.tv_sec)) {
+       diff_usecs = timeval_diff_usecs(&ioloop_timeval, &tv_old);
+       if (unlikely(diff_usecs < 0)) {
                /* time moved backwards */
-               io_loops_timeouts_update(-(long)(ioloop_time -
-                                                ioloop_timeval.tv_sec));
-               ioloop->time_moved_callback(ioloop_time,
-                                           ioloop_timeval.tv_sec);
+               io_loops_timeouts_update(diff_usecs);
+               if (unlikely(ioloop_time > ioloop_timeval.tv_sec)) {
+                       ioloop->time_moved_callback(ioloop_time,
+                                                   ioloop_timeval.tv_sec);
+               }
                i_assert(ioloop == current_ioloop);
                /* the callback may have slept, so check the time again. */
                if (gettimeofday(&ioloop_timeval, NULL) < 0)
                        i_fatal("gettimeofday(): %m");
        } else {
-               if (unlikely(ioloop_timeval.tv_sec >
-                            ioloop->next_max_time)) {
-                       io_loops_timeouts_update(ioloop_timeval.tv_sec -
-                                                ioloop->next_max_time);
+               diff_usecs = timeval_diff_usecs(&ioloop->next_max_time,
+                                               &ioloop_timeval);
+               if (unlikely(diff_usecs < 0)) {
+                       io_loops_timeouts_update(-diff_usecs);
                        /* time moved forwards */
-                       ioloop->time_moved_callback(ioloop->next_max_time,
-                                                   ioloop_timeval.tv_sec);
+                       if (unlikely(ioloop_timeval.tv_sec >
+                                    ioloop->next_max_time.tv_sec)) {
+                               ioloop->time_moved_callback(
+                                       ioloop->next_max_time.tv_sec,
+                                       ioloop_timeval.tv_sec);
+                       }
                        i_assert(ioloop == current_ioloop);
                }
                ioloop_add_wait_time(ioloop);