[tor-commits] [tor/master] Infrastructure for replacing global periodic events in main.c

nickm at torproject.org nickm at torproject.org
Tue Nov 17 13:28:57 UTC 2015


commit fbeff307f7780b26c9645ec7dbd685807add6581
Author: Kevin Butler <haqkrs at gmail.com>
Date:   Mon Nov 2 09:48:18 2015 -0500

    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.)
---
 src/or/include.am |    2 +
 src/or/periodic.c |  118 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/or/periodic.h |   54 ++++++++++++++++++++++++
 3 files changed, 174 insertions(+)

diff --git a/src/or/include.am b/src/or/include.am
index d0e955f..264c4ae 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -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					\
diff --git a/src/or/periodic.c b/src/or/periodic.c
new file mode 100644
index 0000000..6fa1d8a
--- /dev/null
+++ b/src/or/periodic.c
@@ -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);
+  }
+}
diff --git a/src/or/periodic.h b/src/or/periodic.h
new file mode 100644
index 0000000..7d5b1b4
--- /dev/null
+++ b/src/or/periodic.h
@@ -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
+





More information about the tor-commits mailing list