Coverage Report

Created: 2026-03-08 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tor/src/lib/evloop/timers.c
Line
Count
Source
1
/* Copyright (c) 2016-2021, 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
 *   https://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_t {
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 COCCI
60
#define TIMEOUT_PUBLIC
61
#elif defined(__GNUC__)
62
/* We're not exposing any of the functions outside this file. */
63
#define TIMEOUT_PUBLIC __attribute__((__unused__)) static
64
#else
65
/* We're not exposing any of the functions outside this file. */
66
#define TIMEOUT_PUBLIC static
67
#endif /* defined(COCCI) || ... */
68
/* We're not using periodic events. */
69
#define TIMEOUT_DISABLE_INTERVALS
70
/* We always know the global_timeouts object, so we don't need each timeout
71
 * to keep a pointer to it. */
72
#define TIMEOUT_DISABLE_RELATIVE_ACCESS
73
/* We're providing our own struct timeout_cb_t. */
74
#define TIMEOUT_CB_OVERRIDE
75
/* We're going to support timers that are pretty far out in advance. Making
76
 * this big can be inefficient, but having a significant number of timers
77
 * above TIMEOUT_MAX can also be super-inefficient. Choosing 5 here sets
78
 * timeout_max to 2^30 ticks, or 29 hours with our value for USEC_PER_TICK */
79
0
#define WHEEL_NUM 5
80
#if SIZEOF_VOID_P == 4
81
/* On 32-bit platforms, we want to override wheel_bit, so that timeout.c will
82
 * use 32-bit math. */
83
#define WHEEL_BIT 5
84
#endif
85
86
#include "ext/timeouts/timeout.c"
87
88
static struct timeouts *global_timeouts = NULL;
89
static struct mainloop_event_t *global_timer_event = NULL;
90
91
static monotime_t start_of_time;
92
93
/** We need to choose this value carefully.  Because we're using timer wheels,
94
 * it actually costs us to have extra resolution we don't use.  So for now,
95
 * I'm going to define our resolution as .1 msec, and hope that's good enough.
96
 *
97
 * Note that two of the most popular libevent backends (epoll without timerfd,
98
 * and windows select), simply can't support sub-millisecond resolution,
99
 * do this is optimistic for a lot of users.
100
 */
101
0
#define USEC_PER_TICK 100
102
103
/** One million microseconds in a second */
104
0
#define USEC_PER_SEC 1000000
105
106
/** Check at least once every N seconds. */
107
0
#define MIN_CHECK_SECONDS 3600
108
109
/** Check at least once every N ticks. */
110
#define MIN_CHECK_TICKS \
111
0
  (((timeout_t)MIN_CHECK_SECONDS) * (1000000 / USEC_PER_TICK))
112
113
/**
114
 * Convert the timeval in <b>tv</b> to a timeout_t, and return it.
115
 *
116
 * The output resolution is set by USEC_PER_TICK. Only use this to convert
117
 * delays to number of ticks; the time represented by 0 is undefined.
118
 */
119
static timeout_t
120
tv_to_timeout(const struct timeval *tv)
121
0
{
122
0
  uint64_t usec = tv->tv_usec;
123
0
  usec += ((uint64_t)USEC_PER_SEC) * tv->tv_sec;
124
0
  return usec / USEC_PER_TICK;
125
0
}
126
127
/**
128
 * Convert the timeout in <b>t</b> to a timeval in <b>tv_out</b>. Only
129
 * use this for delays, not absolute times.
130
 */
131
static void
132
timeout_to_tv(timeout_t t, struct timeval *tv_out)
133
0
{
134
0
  t *= USEC_PER_TICK;
135
0
  tv_out->tv_usec = (int)(t % USEC_PER_SEC);
136
0
  tv_out->tv_sec = (time_t)(t / USEC_PER_SEC);
137
0
}
138
139
/**
140
 * Update the timer <b>tv</b> to the current time in <b>tv</b>.
141
 */
142
static void
143
timer_advance_to_cur_time(const monotime_t *now)
144
0
{
145
0
  timeout_t cur_tick = CEIL_DIV(monotime_diff_usec(&start_of_time, now),
146
0
                                USEC_PER_TICK);
147
0
  timeouts_update(global_timeouts, cur_tick);
148
0
}
149
150
/**
151
 * Adjust the time at which the libevent timer should fire based on
152
 * the next-expiring time in <b>global_timeouts</b>
153
 */
154
static void
155
libevent_timer_reschedule(void)
156
0
{
157
0
  monotime_t now;
158
0
  monotime_get(&now);
159
0
  timer_advance_to_cur_time(&now);
160
161
0
  timeout_t delay = timeouts_timeout(global_timeouts);
162
163
0
  struct timeval d;
164
0
  if (delay > MIN_CHECK_TICKS)
165
0
    delay = MIN_CHECK_TICKS;
166
0
  timeout_to_tv(delay, &d);
167
0
  mainloop_event_schedule(global_timer_event, &d);
168
0
}
169
170
/** Run the callback of every timer that has expired, based on the current
171
 * output of monotime_get(). */
172
STATIC void
173
timers_run_pending(void)
174
0
{
175
0
  monotime_t now;
176
0
  monotime_get(&now);
177
0
  timer_advance_to_cur_time(&now);
178
179
0
  tor_timer_t *t;
180
0
  while ((t = timeouts_get(global_timeouts))) {
181
0
    t->callback.cb(t, t->callback.arg, &now);
182
0
  }
183
0
}
184
185
/**
186
 * Invoked when the libevent timer has expired: see which tor_timer_t events
187
 * have fired, activate their callbacks, and reschedule the libevent timer.
188
 */
189
static void
190
libevent_timer_callback(mainloop_event_t *ev, void *arg)
191
0
{
192
0
  (void)ev;
193
0
  (void)arg;
194
195
0
  timers_run_pending();
196
197
0
  libevent_timer_reschedule();
198
0
}
199
200
/**
201
 * Initialize the timers subsystem.  Requires that libevent has already been
202
 * initialized.
203
 */
204
void
205
timers_initialize(void)
206
0
{
207
0
  if (BUG(global_timeouts))
208
0
    return; // LCOV_EXCL_LINE
209
210
0
  timeout_error_t err = 0;
211
0
  global_timeouts = timeouts_open(0, &err);
212
0
  if (!global_timeouts) {
213
    // LCOV_EXCL_START -- this can only fail on malloc failure.
214
0
    log_err(LD_BUG, "Unable to open timer backend: %s", strerror(err));
215
0
    tor_assert(0);
216
    // LCOV_EXCL_STOP
217
0
  }
218
219
0
  monotime_init();
220
0
  monotime_get(&start_of_time);
221
222
0
  mainloop_event_t *timer_event;
223
0
  timer_event = mainloop_event_new(libevent_timer_callback, NULL);
224
0
  tor_assert(timer_event);
225
0
  global_timer_event = timer_event;
226
227
0
  libevent_timer_reschedule();
228
0
}
229
230
/**
231
 * Release all storage held in the timers subsystem.  Does not fire timers.
232
 */
233
void
234
timers_shutdown(void)
235
0
{
236
0
  if (global_timer_event) {
237
0
    mainloop_event_free(global_timer_event);
238
0
    global_timer_event = NULL;
239
0
  }
240
0
  if (global_timeouts) {
241
0
    timeouts_close(global_timeouts);
242
0
    global_timeouts = NULL;
243
0
  }
244
0
}
245
246
/**
247
 * Allocate and return a new timer, with given callback and argument.
248
 */
249
tor_timer_t *
250
timer_new(timer_cb_fn_t cb, void *arg)
251
0
{
252
0
  tor_timer_t *t = tor_malloc(sizeof(tor_timer_t));
253
0
  timeout_init(t, 0);
254
0
  timer_set_cb(t, cb, arg);
255
0
  return t;
256
0
}
257
258
/**
259
 * Release all storage held by <b>t</b>, and unschedule it if was already
260
 * scheduled.
261
 */
262
void
263
timer_free_(tor_timer_t *t)
264
0
{
265
0
  if (! t)
266
0
    return;
267
268
0
  timeouts_del(global_timeouts, t);
269
0
  tor_free(t);
270
0
}
271
272
/**
273
 * Change the callback and argument associated with a timer <b>t</b>.
274
 */
275
void
276
timer_set_cb(tor_timer_t *t, timer_cb_fn_t cb, void *arg)
277
0
{
278
0
  t->callback.cb = cb;
279
0
  t->callback.arg = arg;
280
0
}
281
282
/**
283
 * Set *<b>cb_out</b> (if provided) to this timer's callback function,
284
 * and *<b>arg_out</b> (if provided) to this timer's callback argument.
285
 */
286
void
287
timer_get_cb(const tor_timer_t *t,
288
             timer_cb_fn_t *cb_out, void **arg_out)
289
0
{
290
0
  if (cb_out)
291
0
    *cb_out = t->callback.cb;
292
0
  if (arg_out)
293
0
    *arg_out = t->callback.arg;
294
0
}
295
296
/**
297
 * Schedule the timer t to fire at the current time plus a delay of
298
 * <b>delay</b> microseconds.  All times are relative to monotime_get().
299
 */
300
void
301
timer_schedule(tor_timer_t *t, const struct timeval *tv)
302
0
{
303
0
  const timeout_t delay = tv_to_timeout(tv);
304
305
0
  monotime_t now;
306
0
  monotime_get(&now);
307
0
  timer_advance_to_cur_time(&now);
308
309
  /* Take the old timeout value. */
310
0
  timeout_t to = timeouts_timeout(global_timeouts);
311
312
0
  timeouts_add(global_timeouts, t, delay);
313
314
  /* Should we update the libevent timer? */
315
0
  if (to <= delay) {
316
0
    return; /* we're already going to fire before this timer would trigger. */
317
0
  }
318
0
  libevent_timer_reschedule();
319
0
}
320
321
/**
322
 * Cancel the timer <b>t</b> if it is currently scheduled.  (It's okay to call
323
 * this on an unscheduled timer.
324
 */
325
void
326
timer_disable(tor_timer_t *t)
327
0
{
328
0
  timeouts_del(global_timeouts, t);
329
  /* We don't reschedule the libevent timer here, since it's okay if it fires
330
   * early. */
331
0
}