mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 12:23:32 +01:00
Infrastructure for replacing global periodic events in main.c
(This is from Kevin's bug3199 patch series; nick extracted it into a new file and changed the interface a little, then did some API tweaks on it.)
This commit is contained in:
parent
faba114a34
commit
fbeff307f7
@ -63,6 +63,7 @@ LIBTOR_A_SOURCES = \
|
||||
src/or/onion_fast.c \
|
||||
src/or/onion_tap.c \
|
||||
src/or/transports.c \
|
||||
src/or/periodic.c \
|
||||
src/or/policies.c \
|
||||
src/or/reasons.c \
|
||||
src/or/relay.c \
|
||||
@ -173,6 +174,7 @@ ORHEADERS = \
|
||||
src/or/onion_tap.h \
|
||||
src/or/or.h \
|
||||
src/or/transports.h \
|
||||
src/or/periodic.h \
|
||||
src/or/policies.h \
|
||||
src/or/reasons.h \
|
||||
src/or/relay.h \
|
||||
|
118
src/or/periodic.c
Normal file
118
src/or/periodic.c
Normal file
@ -0,0 +1,118 @@
|
||||
/* Copyright (c) 2015, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#include "or.h"
|
||||
#include "config.h"
|
||||
#include "periodic.h"
|
||||
|
||||
static const int MAX_INTERVAL = 10 * 365 * 86400;
|
||||
|
||||
/** DOCDOC */
|
||||
static void
|
||||
periodic_event_set_interval(periodic_event_item_t *event,
|
||||
time_t next_interval)
|
||||
{
|
||||
/** update the interval time if it's changed */
|
||||
if (next_interval != event->interval) {
|
||||
tor_assert(next_interval < MAX_INTERVAL);
|
||||
struct timeval tv;
|
||||
tv.tv_sec = next_interval;
|
||||
tv.tv_usec = 0;
|
||||
event->interval = (int)next_interval;
|
||||
periodic_timer_update_interval(event->timer, &tv);
|
||||
}
|
||||
}
|
||||
|
||||
/** Wraps dispatches for periodic events, <b>data</b> will be a pointer to the
|
||||
* event that needs to be called */
|
||||
static void
|
||||
periodic_event_dispatch(periodic_timer_t *timer, void *data)
|
||||
{
|
||||
periodic_event_item_t *event = data;
|
||||
tor_assert(timer == event->timer);
|
||||
|
||||
time_t now = time(NULL);
|
||||
const or_options_t *options = get_options();
|
||||
int r = event->fn(now, options);
|
||||
int next_interval = 0;
|
||||
|
||||
/* update the last run time if action was taken */
|
||||
if (r==0) {
|
||||
log_err(LD_BUG, "Invalid return value for periodic event from %s.",
|
||||
event->name);
|
||||
tor_assert(r != 0);
|
||||
} else if (r > 0) {
|
||||
event->last_action_time = now;
|
||||
/* If the event is meant to happen after ten years, that's likely
|
||||
* a bug, and somebody gave an absolute time rather than an interval.
|
||||
*/
|
||||
tor_assert(r < MAX_INTERVAL);
|
||||
next_interval = r;
|
||||
} else {
|
||||
/* no action was taken, it is likely a precondition failed,
|
||||
* we should reschedule for next second incase the precondition
|
||||
* passes then */
|
||||
next_interval = 1;
|
||||
}
|
||||
|
||||
periodic_event_set_interval(event, next_interval);
|
||||
|
||||
log_info(LD_GENERAL, "Dispatching %s", event->name);
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
void
|
||||
periodic_event_reschedule(periodic_event_item_t *event)
|
||||
{
|
||||
periodic_event_set_interval(event, 1);
|
||||
}
|
||||
|
||||
/** Handles initial dispatch for periodic events. It should happen 1 second
|
||||
* after the events are created to mimic behaviour before #3199's refactor */
|
||||
void
|
||||
periodic_event_launch(periodic_event_item_t *event)
|
||||
{
|
||||
if (event->timer) { /** Already setup? This is a bug */
|
||||
log_err(LD_BUG, "Initial dispatch should only be done once.");
|
||||
tor_assert(0);
|
||||
}
|
||||
|
||||
struct timeval interval;
|
||||
interval.tv_sec = event->interval;
|
||||
interval.tv_usec = 0;
|
||||
|
||||
periodic_timer_t *timer = periodic_timer_new(tor_libevent_get_base(),
|
||||
&interval,
|
||||
periodic_event_dispatch,
|
||||
event);
|
||||
tor_assert(timer);
|
||||
event->timer = timer;
|
||||
|
||||
// Initial dispatch
|
||||
periodic_event_dispatch(timer, event);
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
void
|
||||
periodic_event_destroy(periodic_event_item_t *event)
|
||||
{
|
||||
if (!event)
|
||||
return;
|
||||
periodic_timer_free(event->timer);
|
||||
event->timer = 0;
|
||||
event->interval = 0;
|
||||
event->last_action_time = 0;
|
||||
}
|
||||
|
||||
/** DOCDOC */
|
||||
void
|
||||
periodic_event_assert_in_range(periodic_event_item_t *ev,
|
||||
time_t start, time_t end)
|
||||
{
|
||||
if (ev->last_action_time < start-1 || ev->last_action_time > end) {
|
||||
log_err(LD_BUG, "[Refactor Bug] Missed an interval in a range,"
|
||||
"Got %lu, wanted %lu <= x <= %lu.", ev->last_action_time,
|
||||
start, end);
|
||||
tor_assert(0);
|
||||
}
|
||||
}
|
54
src/or/periodic.h
Normal file
54
src/or/periodic.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* Copyright (c) 2015, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#ifndef TOR_PERIODIC_H
|
||||
#define TOR_PERIODIC_H
|
||||
|
||||
/** Callback function for a periodic event to take action.
|
||||
* The return value influences the next time the function will get called.
|
||||
* Return -1 to not update <b>last_action_time</b> and be polled again in
|
||||
* the next second. If a positive value is returned it will update the
|
||||
* interval time. If the returned value is larger than <b>now</b> then it
|
||||
* is assumed to be a future time to poll again. */
|
||||
typedef int (*periodic_event_helper_t)(time_t now,
|
||||
const or_options_t *options);
|
||||
|
||||
|
||||
/** A single item for the periodic-events-function table. */
|
||||
typedef struct periodic_event_item_t {
|
||||
periodic_event_helper_t fn; /**< The function to run the event */
|
||||
int interval; /**< The interval for running the function (In seconds). */
|
||||
time_t last_action_time; /**< The last time the function did something */
|
||||
periodic_timer_t *timer; /**< Timer object for this event */
|
||||
const char *name; /**< Name of the function -- for debug */
|
||||
} periodic_event_item_t;
|
||||
|
||||
/** events will get their interval from first execution */
|
||||
#define PERIODIC_EVENT(fn) { fn##_callback, 0, 0, NULL, #fn }
|
||||
|
||||
#if 0
|
||||
/** Refactor test, check the last_action_time was now or (now - delta - 1)
|
||||
* It returns an incremented <b>now</b> value and accounts for the current
|
||||
* implementation's off by one error in it's comparisons. */
|
||||
#define INCREMENT_DELTA_AND_TEST(id, now, delta) \
|
||||
(now+delta); \
|
||||
STMT_BEGIN \
|
||||
periodic_event_item_t *ev = &periodic_events[id]; \
|
||||
if (ev->last_action_time != now - delta - 1 && \
|
||||
ev->last_action_time != now) { \
|
||||
log_err(LD_BUG, "[Refactor Bug] Missed an interval " \
|
||||
"for %s, Got %lu, wanted %lu or %lu.", ev->name, \
|
||||
ev->last_action_time, now, now-delta); \
|
||||
tor_assert(0); \
|
||||
} \
|
||||
STMT_END
|
||||
#endif
|
||||
|
||||
void periodic_event_assert_in_range(periodic_event_item_t *event,
|
||||
time_t start, time_t end);
|
||||
void periodic_event_launch(periodic_event_item_t *event);
|
||||
void periodic_event_destroy(periodic_event_item_t *event);
|
||||
void periodic_event_reschedule(periodic_event_item_t *event);
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user