tor  0.4.1.0-alpha-dev
timers.c
Go to the documentation of this file.
1 /* Copyright (c) 2016-2019, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
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 
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 
99 #define USEC_PER_TICK 100
100 
102 #define USEC_PER_SEC 1000000
103 
105 #define MIN_CHECK_SECONDS 3600
106 
108 #define MIN_CHECK_TICKS \
109  (((timeout_t)MIN_CHECK_SECONDS) * (1000000 / USEC_PER_TICK))
110 
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 
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 
140 static void
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 
152 static void
154 {
155  monotime_t now;
156  monotime_get(&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 
170 STATIC void
172 {
173  monotime_t now;
174  monotime_get(&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 
187 static void
189 {
190  (void)ev;
191  (void)arg;
192 
194 
196 }
197 
202 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 
226 }
227 
231 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 
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 
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 
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 
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 
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);
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  }
317 }
318 
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 }
void timers_initialize(void)
Definition: timers.c:203
void timer_disable(tor_timer_t *t)
Definition: timers.c:324
void monotime_init(void)
Definition: compat_time.c:739
STATIC void timers_run_pending(void)
Definition: timers.c:171
Functions and types for monotonic times.
static void timer_advance_to_cur_time(const monotime_t *now)
Definition: timers.c:141
#define MIN_CHECK_TICKS
Definition: timers.c:108
int64_t monotime_diff_usec(const monotime_t *start, const monotime_t *end)
Definition: compat_time.c:765
static void libevent_timer_reschedule(void)
Definition: timers.c:153
#define tor_free(p)
Definition: malloc.h:52
#define USEC_PER_SEC
Definition: timers.c:102
void monotime_get(monotime_t *out)
Headers for util_malloc.c.
tor_assert(buffer)
static void timeout_to_tv(timeout_t t, struct timeval *tv_out)
Definition: timers.c:130
void timer_get_cb(const tor_timer_t *t, timer_cb_fn_t *cb_out, void **arg_out)
Definition: timers.c:285
void timer_schedule(tor_timer_t *t, const struct timeval *tv)
Definition: timers.c:299
static timeout_t tv_to_timeout(const struct timeval *tv)
Definition: timers.c:118
void timers_shutdown(void)
Definition: timers.c:232
#define USEC_PER_TICK
Definition: timers.c:99
Header for muldiv.c.
tor_timer_t * timer_new(timer_cb_fn_t cb, void *arg)
Definition: timers.c:248
Header for timers.c.
void timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg)
Definition: timers.c:274
mainloop_event_t * mainloop_event_new(void(*cb)(mainloop_event_t *, void *), void *userdata)
int mainloop_event_schedule(mainloop_event_t *event, const struct timeval *tv)
void timer_free_(tor_timer_t *t)
Definition: timers.c:261
Headers for log.c.
Header for compat_libevent.c.
Macros to manage assertions, fatal and non-fatal.
static void libevent_timer_callback(mainloop_event_t *ev, void *arg)
Definition: timers.c:188
#define LD_BUG
Definition: log.h:82