Tor 0.4.9.0-alpha-dev
periodic.c
Go to the documentation of this file.
1/* Copyright (c) 2015-2021, The Tor Project, Inc. */
2/* See LICENSE for licensing information */
3
4/**
5 * \file periodic.c
6 *
7 * \brief Generic backend for handling periodic events.
8 *
9 * The events in this module are used to track items that need
10 * to fire once every N seconds, possibly picking a new interval each time
11 * that they fire. See periodic_events[] in mainloop.c for examples.
12 *
13 * This module manages a global list of periodic_event_item_t objects,
14 * each corresponding to a single event. To register an event, pass it to
15 * periodic_events_register() when initializing your subsystem.
16 *
17 * Registering an event makes the periodic event subsystem know about it, but
18 * doesn't cause the event to get created immediately. Before the event can
19 * be started, periodic_event_connect_all() must be called by mainloop.c to
20 * connect all the events to Libevent.
21 *
22 * We expect that periodic_event_item_t objects will be statically allocated;
23 * we set them up and tear them down here, but we don't take ownership of
24 * them.
25 */
26
27#include "core/or/or.h"
29#include "app/config/config.h"
32
33/** We disable any interval greater than this number of seconds, on the
34 * grounds that it is probably an absolute time mistakenly passed in as a
35 * relative time.
36 */
37static const int MAX_INTERVAL = 10 * 365 * 86400;
38
39/**
40 * Global list of periodic events that have been registered with
41 * <b>periodic_event_register</b>.
42 **/
44
45/** Set the event <b>event</b> to run in <b>next_interval</b> seconds from
46 * now. */
47static void
49 time_t next_interval)
50{
51 tor_assert(next_interval < MAX_INTERVAL);
52 struct timeval tv;
53 tv.tv_sec = next_interval;
54 tv.tv_usec = 0;
55 mainloop_event_schedule(event->ev, &tv);
56}
57
58/** Wraps dispatches for periodic events, <b>data</b> will be a pointer to the
59 * event that needs to be called */
60static void
62{
63 periodic_event_item_t *event = data;
64 tor_assert(ev == event->ev);
65
66 time_t now = time(NULL);
68 const or_options_t *options = get_options();
69// log_debug(LD_GENERAL, "Dispatching %s", event->name);
70 int r = event->fn(now, options);
71 int next_interval = 0;
72
73 if (!periodic_event_is_enabled(event)) {
74 /* The event got disabled from inside its callback, or before: no need to
75 * reschedule. */
76 return;
77 }
78
79 /* update the last run time if action was taken */
80 if (r==0) {
81 log_err(LD_BUG, "Invalid return value for periodic event from %s.",
82 event->name);
83 tor_assert(r != 0);
84 } else if (r > 0) {
85 event->last_action_time = now;
86 /* If the event is meant to happen after ten years, that's likely
87 * a bug, and somebody gave an absolute time rather than an interval.
88 */
90 next_interval = r;
91 } else {
92 /* no action was taken, it is likely a precondition failed,
93 * we should reschedule for next second in case the precondition
94 * passes then */
95 next_interval = 1;
96 }
97
98// log_debug(LD_GENERAL, "Scheduling %s for %d seconds", event->name,
99// next_interval);
100 struct timeval tv = { next_interval , 0 };
102}
103
104/** Schedules <b>event</b> to run as soon as possible from now. */
105void
107{
108 /* Don't reschedule a disabled or uninitialized event. */
109 if (event->ev && periodic_event_is_enabled(event)) {
111 }
112}
113
114/** Connects a periodic event to the Libevent backend. Does not launch the
115 * event immediately. */
116void
118{
119 if (event->ev) { /* Already setup? This is a bug */
120 log_err(LD_BUG, "Initial dispatch should only be done once.");
121 tor_assert(0);
122 }
123
125 event);
126 tor_assert(event->ev);
127}
128
129/** Handles initial dispatch for periodic events. It should happen 1 second
130 * after the events are created to mimic behaviour before #3199's refactor */
131void
133{
134 if (! event->ev) { /* Not setup? This is a bug */
135 log_err(LD_BUG, "periodic_event_launch without periodic_event_connect");
136 tor_assert(0);
137 }
138 /* Event already enabled? This is a bug */
139 if (periodic_event_is_enabled(event)) {
140 log_err(LD_BUG, "periodic_event_launch on an already enabled event");
141 tor_assert(0);
142 }
143
144 // Initial dispatch
145 event->enabled = 1;
146 periodic_event_dispatch(event->ev, event);
147}
148
149/** Disconnect and unregister the periodic event in <b>event</b> */
150static void
152{
153 if (!event)
154 return;
155
156 /* First disable the event so we first cancel the event and set its enabled
157 * flag properly. */
159
160 mainloop_event_free(event->ev);
161 event->last_action_time = 0;
162}
163
164/** Enable the given event by setting its "enabled" flag and scheduling it to
165 * run immediately in the event loop. This can be called for an event that is
166 * already enabled. */
167void
169{
170 tor_assert(event);
171 /* Safely and silently ignore if this event is already enabled. */
172 if (periodic_event_is_enabled(event)) {
173 return;
174 }
175
176 tor_assert(event->ev);
177 event->enabled = 1;
179}
180
181/** Disable the given event which means the event is destroyed and then the
182 * event's enabled flag is unset. This can be called for an event that is
183 * already disabled. */
184void
186{
187 tor_assert(event);
188 /* Safely and silently ignore if this event is already disabled. */
189 if (!periodic_event_is_enabled(event)) {
190 return;
191 }
193 event->enabled = 0;
194}
195
196/**
197 * Disable an event, then schedule it to run once.
198 * Do nothing if the event was already disabled.
199 */
200void
202{
203 tor_assert(event);
204 if (!periodic_event_is_enabled(event))
205 return;
206
208
210}
211
212/**
213 * Add <b>item</b> to the list of periodic events.
214 *
215 * Note that <b>item</b> should be statically allocated: we do not
216 * take ownership of it.
217 **/
218void
220{
223
225 return;
226
228}
229
230/**
231 * Make all registered periodic events connect to the libevent backend.
232 */
233void
235{
237 return;
238
240 if (item->ev)
241 continue;
243 } SMARTLIST_FOREACH_END(item);
244}
245
246/**
247 * Reset all the registered periodic events so we'll do all our actions again
248 * as if we just started up.
249 *
250 * Useful if our clock just moved back a long time from the future,
251 * so we don't wait until that future arrives again before acting.
252 */
253void
255{
257 return;
258
260 if (!item->ev)
261 continue;
262
264 } SMARTLIST_FOREACH_END(item);
265}
266
267/**
268 * Return the registered periodic event whose name is <b>name</b>.
269 * Return NULL if no such event is found.
270 */
273{
275 return NULL;
276
278 if (strcmp(name, item->name) == 0)
279 return item;
280 } SMARTLIST_FOREACH_END(item);
281 return NULL;
282}
283
284/**
285 * Start or stop registered periodic events, depending on our current set of
286 * roles.
287 *
288 * Invoked when our list of roles, or the net_disabled flag has changed.
289 **/
290void
291periodic_events_rescan_by_roles(int roles, bool net_disabled)
292{
294 return;
295
297 if (!item->ev)
298 continue;
299
300 int enable = !!(item->roles & roles);
301
302 /* Handle the event flags. */
303 if (net_disabled &&
304 (item->flags & PERIODIC_EVENT_FLAG_NEED_NET)) {
305 enable = 0;
306 }
307
308 /* Enable the event if needed. It is safe to enable an event that was
309 * already enabled. Same goes for disabling it. */
310 if (enable) {
311 log_debug(LD_GENERAL, "Launching periodic event %s", item->name);
313 } else {
314 log_debug(LD_GENERAL, "Disabling periodic event %s", item->name);
315 if (item->flags & PERIODIC_EVENT_FLAG_RUN_ON_DISABLE) {
317 } else {
319 }
320 }
321 } SMARTLIST_FOREACH_END(item);
322}
323
324/**
325 * Invoked at shutdown: disconnect and unregister all periodic events.
326 *
327 * Does not free the periodic_event_item_t object themselves, because we do
328 * not own them.
329 */
330void
332{
334 return;
335
338 } SMARTLIST_FOREACH_END(item);
339
340 smartlist_free(the_periodic_events);
341}
342
343#define LONGEST_TIMER_PERIOD (30 * 86400)
344/** Helper: Return the number of seconds between <b>now</b> and <b>next</b>,
345 * clipped to the range [1 second, LONGEST_TIMER_PERIOD].
346 *
347 * We use this to answer the question, "how many seconds is it from now until
348 * next" in periodic timer callbacks. Don't use it for other purposes
349 **/
350int
351safe_timer_diff(time_t now, time_t next)
352{
353 if (next > now) {
354 /* There were no computers at signed TIME_MIN (1902 on 32-bit systems),
355 * and nothing that could run Tor. It's a bug if 'next' is around then.
356 * On 64-bit systems with signed TIME_MIN, TIME_MIN is before the Big
357 * Bang. We cannot extrapolate past a singularity, but there was probably
358 * nothing that could run Tor then, either.
359 **/
360 tor_assert(next > TIME_MIN + LONGEST_TIMER_PERIOD);
361
362 if (next - LONGEST_TIMER_PERIOD > now)
363 return LONGEST_TIMER_PERIOD;
364 return (int)(next - now);
365 } else {
366 return 1;
367 }
368}
void mainloop_event_cancel(mainloop_event_t *event)
int mainloop_event_schedule(mainloop_event_t *event, const struct timeval *tv)
mainloop_event_t * mainloop_event_new(void(*cb)(mainloop_event_t *, void *), void *userdata)
void mainloop_event_activate(mainloop_event_t *event)
Header for compat_libevent.c.
const char * name
Definition: config.c:2462
const or_options_t * get_options(void)
Definition: config.c:944
Header file for config.c.
#define LD_BUG
Definition: log.h:86
#define LD_GENERAL
Definition: log.h:62
void update_current_time(time_t now)
Definition: mainloop.c:2226
Header file for mainloop.c.
Master header file for Tor-specific functionality.
void periodic_event_disable(periodic_event_item_t *event)
Definition: periodic.c:185
static const int MAX_INTERVAL
Definition: periodic.c:37
void periodic_events_rescan_by_roles(int roles, bool net_disabled)
Definition: periodic.c:291
periodic_event_item_t * periodic_events_find(const char *name)
Definition: periodic.c:272
static void periodic_event_dispatch(mainloop_event_t *ev, void *data)
Definition: periodic.c:61
static void periodic_event_set_interval(periodic_event_item_t *event, time_t next_interval)
Definition: periodic.c:48
void periodic_event_schedule_and_disable(periodic_event_item_t *event)
Definition: periodic.c:201
void periodic_event_enable(periodic_event_item_t *event)
Definition: periodic.c:168
static smartlist_t * the_periodic_events
Definition: periodic.c:43
void periodic_events_connect_all(void)
Definition: periodic.c:234
void periodic_events_register(periodic_event_item_t *item)
Definition: periodic.c:219
void periodic_event_launch(periodic_event_item_t *event)
Definition: periodic.c:132
void periodic_event_connect(periodic_event_item_t *event)
Definition: periodic.c:117
int safe_timer_diff(time_t now, time_t next)
Definition: periodic.c:351
void periodic_events_disconnect_all(void)
Definition: periodic.c:331
void periodic_event_reschedule(periodic_event_item_t *event)
Definition: periodic.c:106
void periodic_events_reset_all(void)
Definition: periodic.c:254
static void periodic_event_disconnect(periodic_event_item_t *event)
Definition: periodic.c:151
Header for periodic.c.
int smartlist_contains(const smartlist_t *sl, const void *element)
smartlist_t * smartlist_new(void)
void smartlist_add(smartlist_t *sl, void *element)
#define SMARTLIST_FOREACH_BEGIN(sl, type, var)
struct mainloop_event_t * ev
Definition: periodic.h:66
#define tor_assert(expr)
Definition: util_bug.h:103