"Fossies" - the Fresh Open Source Software Archive

Member "tor-0.4.1.6/src/lib/evloop/timers.c" (10 Jun 2019, 8613 Bytes) of package /linux/misc/tor-0.4.1.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "timers.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.3.5.8_vs_0.4.0.5.

    1 /* Copyright (c) 2016-2019, The Tor Project, Inc. */
    2 /* See LICENSE for licensing information */
    3 
    4 /**
    5  * \file timers.c
    6  * \brief Wrapper around William Ahern's fast hierarchical timer wheel
    7  *   implementation, to tie it in with a libevent backend.
    8  *
    9  * Only use these functions from the main thread.
   10  *
   11  * The main advantage of tor_timer_t over using libevent's timers is that
   12  * they're way more efficient if we need to have thousands or millions of
   13  * them.  For more information, see
   14  *   http://www.25thandclement.com/~william/projects/timeout.c.html
   15  *
   16  * Periodic timers are available in the backend, but I've turned them off.
   17  * We can turn them back on if needed.
   18  */
   19 
   20 /* Notes:
   21  *
   22  * Having a way to free all timers on shutdown would free people from the
   23  * need to track them.  Not sure if that's clever though.
   24  *
   25  * In an ideal world, Libevent would just switch to use this backend, and we
   26  * could throw this file away.  But even if Libevent does switch, we'll be
   27  * stuck with legacy libevents for some time.
   28  */
   29 
   30 #include "orconfig.h"
   31 
   32 #define TOR_TIMERS_PRIVATE
   33 
   34 #include "lib/evloop/compat_libevent.h"
   35 #include "lib/evloop/timers.h"
   36 #include "lib/intmath/muldiv.h"
   37 #include "lib/log/log.h"
   38 #include "lib/log/util_bug.h"
   39 #include "lib/malloc/malloc.h"
   40 #include "lib/time/compat_time.h"
   41 
   42 #ifdef HAVE_SYS_TIME_H
   43 #include <sys/time.h>
   44 #endif
   45 
   46 #ifdef _WIN32
   47 // For struct timeval.
   48 #include <winsock2.h>
   49 #endif
   50 
   51 struct timeout_cb {
   52   timer_cb_fn_t cb;
   53   void *arg;
   54 };
   55 
   56 /*
   57  * These definitions are for timeouts.c  and timeouts.h.
   58  */
   59 #ifdef __GNUC__
   60 /* We're not exposing any of the functions outside this file. */
   61 #define TIMEOUT_PUBLIC __attribute__((__unused__)) static
   62 #else
   63 /* We're not exposing any of the functions outside this file. */
   64 #define TIMEOUT_PUBLIC static
   65 #endif /* defined(__GNUC__) */
   66 /* We're not using periodic events. */
   67 #define TIMEOUT_DISABLE_INTERVALS
   68 /* We always know the global_timeouts object, so we don't need each timeout
   69  * to keep a pointer to it. */
   70 #define TIMEOUT_DISABLE_RELATIVE_ACCESS
   71 /* We're providing our own struct timeout_cb. */
   72 #define TIMEOUT_CB_OVERRIDE
   73 /* We're going to support timers that are pretty far out in advance. Making
   74  * this big can be inefficient, but having a significant number of timers
   75  * above TIMEOUT_MAX can also be super-inefficient. Choosing 5 here sets
   76  * timeout_max to 2^30 ticks, or 29 hours with our value for USEC_PER_TICK */
   77 #define WHEEL_NUM 5
   78 #if SIZEOF_VOID_P == 4
   79 /* On 32-bit platforms, we want to override wheel_bit, so that timeout.c will
   80  * use 32-bit math. */
   81 #define WHEEL_BIT 5
   82 #endif
   83 
   84 #include "ext/timeouts/timeout.c"
   85 
   86 static struct timeouts *global_timeouts = NULL;
   87 static struct mainloop_event_t *global_timer_event = NULL;
   88 
   89 static monotime_t start_of_time;
   90 
   91 /** We need to choose this value carefully.  Because we're using timer wheels,
   92  * it actually costs us to have extra resolution we don't use.  So for now,
   93  * I'm going to define our resolution as .1 msec, and hope that's good enough.
   94  *
   95  * Note that two of the most popular libevent backends (epoll without timerfd,
   96  * and windows select), simply can't support sub-millisecond resolution,
   97  * do this is optimistic for a lot of users.
   98  */
   99 #define USEC_PER_TICK 100
  100 
  101 /** One million microseconds in a second */
  102 #define USEC_PER_SEC 1000000
  103 
  104 /** Check at least once every N seconds. */
  105 #define MIN_CHECK_SECONDS 3600
  106 
  107 /** Check at least once every N ticks. */
  108 #define MIN_CHECK_TICKS \
  109   (((timeout_t)MIN_CHECK_SECONDS) * (1000000 / USEC_PER_TICK))
  110 
  111 /**
  112  * Convert the timeval in <b>tv</b> to a timeout_t, and return it.
  113  *
  114  * The output resolution is set by USEC_PER_TICK. Only use this to convert
  115  * delays to number of ticks; the time represented by 0 is undefined.
  116  */
  117 static timeout_t
  118 tv_to_timeout(const struct timeval *tv)
  119 {
  120   uint64_t usec = tv->tv_usec;
  121   usec += ((uint64_t)USEC_PER_SEC) * tv->tv_sec;
  122   return usec / USEC_PER_TICK;
  123 }
  124 
  125 /**
  126  * Convert the timeout in <b>t</b> to a timeval in <b>tv_out</b>. Only
  127  * use this for delays, not absolute times.
  128  */
  129 static void
  130 timeout_to_tv(timeout_t t, struct timeval *tv_out)
  131 {
  132   t *= USEC_PER_TICK;
  133   tv_out->tv_usec = (int)(t % USEC_PER_SEC);
  134   tv_out->tv_sec = (time_t)(t / USEC_PER_SEC);
  135 }
  136 
  137 /**
  138  * Update the timer <b>tv</b> to the current time in <b>tv</b>.
  139  */
  140 static void
  141 timer_advance_to_cur_time(const monotime_t *now)
  142 {
  143   timeout_t cur_tick = CEIL_DIV(monotime_diff_usec(&start_of_time, now),
  144                                 USEC_PER_TICK);
  145   timeouts_update(global_timeouts, cur_tick);
  146 }
  147 
  148 /**
  149  * Adjust the time at which the libevent timer should fire based on
  150  * the next-expiring time in <b>global_timeouts</b>
  151  */
  152 static void
  153 libevent_timer_reschedule(void)
  154 {
  155   monotime_t now;
  156   monotime_get(&now);
  157   timer_advance_to_cur_time(&now);
  158 
  159   timeout_t delay = timeouts_timeout(global_timeouts);
  160 
  161   struct timeval d;
  162   if (delay > MIN_CHECK_TICKS)
  163     delay = MIN_CHECK_TICKS;
  164   timeout_to_tv(delay, &d);
  165   mainloop_event_schedule(global_timer_event, &d);
  166 }
  167 
  168 /** Run the callback of every timer that has expired, based on the current
  169  * output of monotime_get(). */
  170 STATIC void
  171 timers_run_pending(void)
  172 {
  173   monotime_t now;
  174   monotime_get(&now);
  175   timer_advance_to_cur_time(&now);
  176 
  177   tor_timer_t *t;
  178   while ((t = timeouts_get(global_timeouts))) {
  179     t->callback.cb(t, t->callback.arg, &now);
  180   }
  181 }
  182 
  183 /**
  184  * Invoked when the libevent timer has expired: see which tor_timer_t events
  185  * have fired, activate their callbacks, and reschedule the libevent timer.
  186  */
  187 static void
  188 libevent_timer_callback(mainloop_event_t *ev, void *arg)
  189 {
  190   (void)ev;
  191   (void)arg;
  192 
  193   timers_run_pending();
  194 
  195   libevent_timer_reschedule();
  196 }
  197 
  198 /**
  199  * Initialize the timers subsystem.  Requires that libevent has already been
  200  * initialized.
  201  */
  202 void
  203 timers_initialize(void)
  204 {
  205   if (BUG(global_timeouts))
  206     return; // LCOV_EXCL_LINE
  207 
  208   timeout_error_t err = 0;
  209   global_timeouts = timeouts_open(0, &err);
  210   if (!global_timeouts) {
  211     // LCOV_EXCL_START -- this can only fail on malloc failure.
  212     log_err(LD_BUG, "Unable to open timer backend: %s", strerror(err));
  213     tor_assert(0);
  214     // LCOV_EXCL_STOP
  215   }
  216 
  217   monotime_init();
  218   monotime_get(&start_of_time);
  219 
  220   mainloop_event_t *timer_event;
  221   timer_event = mainloop_event_new(libevent_timer_callback, NULL);
  222   tor_assert(timer_event);
  223   global_timer_event = timer_event;
  224 
  225   libevent_timer_reschedule();
  226 }
  227 
  228 /**
  229  * Release all storage held in the timers subsystem.  Does not fire timers.
  230  */
  231 void
  232 timers_shutdown(void)
  233 {
  234   if (global_timer_event) {
  235     mainloop_event_free(global_timer_event);
  236     global_timer_event = NULL;
  237   }
  238   if (global_timeouts) {
  239     timeouts_close(global_timeouts);
  240     global_timeouts = NULL;
  241   }
  242 }
  243 
  244 /**
  245  * Allocate and return a new timer, with given callback and argument.
  246  */
  247 tor_timer_t *
  248 timer_new(timer_cb_fn_t cb, void *arg)
  249 {
  250   tor_timer_t *t = tor_malloc(sizeof(tor_timer_t));
  251   timeout_init(t, 0);
  252   timer_set_cb(t, cb, arg);
  253   return t;
  254 }
  255 
  256 /**
  257  * Release all storage held by <b>t</b>, and unschedule it if was already
  258  * scheduled.
  259  */
  260 void
  261 timer_free_(tor_timer_t *t)
  262 {
  263   if (! t)
  264     return;
  265 
  266   timeouts_del(global_timeouts, t);
  267   tor_free(t);
  268 }
  269 
  270 /**
  271  * Change the callback and argument associated with a timer <b>t</b>.
  272  */
  273 void
  274 timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg)
  275 {
  276   t->callback.cb = cb;
  277   t->callback.arg = arg;
  278 }
  279 
  280 /**
  281  * Set *<b>cb_out</b> (if provided) to this timer's callback function,
  282  * and *<b>arg_out</b> (if provided) to this timer's callback argument.
  283  */
  284 void
  285 timer_get_cb(const tor_timer_t *t,
  286              timer_cb_fn_t *cb_out, void **arg_out)
  287 {
  288   if (cb_out)
  289     *cb_out = t->callback.cb;
  290   if (arg_out)
  291     *arg_out = t->callback.arg;
  292 }
  293 
  294 /**
  295  * Schedule the timer t to fire at the current time plus a delay of
  296  * <b>delay</b> microseconds.  All times are relative to monotime_get().
  297  */
  298 void
  299 timer_schedule(tor_timer_t *t, const struct timeval *tv)
  300 {
  301   const timeout_t delay = tv_to_timeout(tv);
  302 
  303   monotime_t now;
  304   monotime_get(&now);
  305   timer_advance_to_cur_time(&now);
  306 
  307   /* Take the old timeout value. */
  308   timeout_t to = timeouts_timeout(global_timeouts);
  309 
  310   timeouts_add(global_timeouts, t, delay);
  311 
  312   /* Should we update the libevent timer? */
  313   if (to <= delay) {
  314     return; /* we're already going to fire before this timer would trigger. */
  315   }
  316   libevent_timer_reschedule();
  317 }
  318 
  319 /**
  320  * Cancel the timer <b>t</b> if it is currently scheduled.  (It's okay to call
  321  * this on an unscheduled timer.
  322  */
  323 void
  324 timer_disable(tor_timer_t *t)
  325 {
  326   timeouts_del(global_timeouts, t);
  327   /* We don't reschedule the libevent timer here, since it's okay if it fires
  328    * early. */
  329 }