[tor-commits] [tor/master] Give responsibility for waking up from DORMANT to a mainloop event

nickm at torproject.org nickm at torproject.org
Thu May 10 13:07:01 UTC 2018


commit a1a7ebfb8dbb9b104771e99571b6a60c70ee1dbe
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed May 9 13:41:04 2018 -0400

    Give responsibility for waking up from DORMANT to a mainloop event
    
    Closes ticket 26064.
---
 changes/ticket26064 |  5 ++++
 src/or/hibernate.c  | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/or/hibernate.h  |  1 +
 src/or/main.c       |  2 ++
 4 files changed, 81 insertions(+)

diff --git a/changes/ticket26064 b/changes/ticket26064
new file mode 100644
index 000000000..6efb8a483
--- /dev/null
+++ b/changes/ticket26064
@@ -0,0 +1,5 @@
+  o Minor features (accounting):
+    - When we become dormant, use a scheduled event to wake up at the right
+      time.  Previously, we would use the per-second timer to check whether
+      to wake up, but we no longer have any per-second timers enabled when
+      the network is disabled. Closes ticket 26064.
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index 98f32adb1..b83167d20 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -52,6 +52,10 @@ static time_t hibernate_end_time = 0;
  * we aren't shutting down. */
 static time_t shutdown_time = 0;
 
+/** A timed event that we'll use when it's time to wake up from
+ * hibernation. */
+static mainloop_event_t *wakeup_event = NULL;
+
 /** Possible accounting periods. */
 typedef enum {
   UNIT_MONTH=1, UNIT_WEEK=2, UNIT_DAY=3,
@@ -131,6 +135,8 @@ static time_t start_of_accounting_period_after(time_t now);
 static time_t start_of_accounting_period_containing(time_t now);
 static void accounting_set_wakeup_time(void);
 static void on_hibernate_state_change(hibernate_state_t prev_state);
+static void hibernate_schedule_wakeup_event(time_t now, time_t end_time);
+static void wakeup_event_callback(mainloop_event_t *ev, void *data);
 
 /**
  * Return the human-readable name for the hibernation state <b>state</b>
@@ -936,6 +942,63 @@ hibernate_go_dormant(time_t now)
 
   or_state_mark_dirty(get_or_state(),
                       get_options()->AvoidDiskWrites ? now+600 : 0);
+
+  hibernate_schedule_wakeup_event(now, hibernate_end_time);
+}
+
+/**
+ * Schedule a mainloop event at <b>end_time</b> to wake up from a dormant
+ * state.  We can't rely on this happening from second_elapsed_callback,
+ * since second_elapsed_callback will be shut down when we're dormant.
+ *
+ * (Note that We might immediately go back to sleep after we set the next
+ * wakeup time.)
+ */
+static void
+hibernate_schedule_wakeup_event(time_t now, time_t end_time)
+{
+  struct timeval delay = { 0, 0 };
+
+  if (now >= end_time) {
+    // In these cases we always wait at least a second, to avoid running
+    // the callback in a tight loop.
+    delay.tv_sec = 1;
+  } else {
+    delay.tv_sec = (end_time - now);
+  }
+
+  if (!wakeup_event) {
+    wakeup_event = mainloop_event_postloop_new(wakeup_event_callback, NULL);
+  }
+
+  mainloop_event_schedule(wakeup_event, &delay);
+}
+
+/**
+ * Called at the end of the interval, or at the wakeup time of the current
+ * interval, to exit the dormant state.
+ **/
+static void
+wakeup_event_callback(mainloop_event_t *ev, void *data)
+{
+  (void) ev;
+  (void) data;
+
+  const time_t now = time(NULL);
+  accounting_run_housekeeping(now);
+  consider_hibernation(now);
+  if (hibernate_state != HIBERNATE_STATE_DORMANT) {
+    /* We woke up, so everything's great here */
+    return;
+  }
+
+  /* We're still dormant. */
+  if (now < interval_wakeup_time)
+    hibernate_end_time = interval_wakeup_time;
+  else
+    hibernate_end_time = interval_end_time;
+
+  hibernate_schedule_wakeup_event(now, hibernate_end_time);
 }
 
 /** Called when hibernate_end_time has arrived. */
@@ -1126,6 +1189,16 @@ on_hibernate_state_change(hibernate_state_t prev_state)
   }
 }
 
+/** Free all resources held by the accounting module */
+void
+accounting_free_all(void)
+{
+  mainloop_event_free(wakeup_event);
+  hibernate_state = HIBERNATE_STATE_INITIAL;
+  hibernate_end_time = 0;
+  shutdown_time = 0;
+}
+
 #ifdef TOR_UNIT_TESTS
 /**
  * Manually change the hibernation state.  Private; used only by the unit
diff --git a/src/or/hibernate.h b/src/or/hibernate.h
index 85fb42864..4bbda6694 100644
--- a/src/or/hibernate.h
+++ b/src/or/hibernate.h
@@ -30,6 +30,7 @@ int getinfo_helper_accounting(control_connection_t *conn,
                               const char *question, char **answer,
                               const char **errmsg);
 uint64_t get_accounting_max_total(void);
+void accounting_free_all(void);
 
 #ifdef HIBERNATE_PRIVATE
 /** Possible values of hibernate_state */
diff --git a/src/or/main.c b/src/or/main.c
index c3505a2d9..9cbe5c8d9 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -3618,6 +3618,8 @@ tor_free_all(int postfork)
   hs_free_all();
   dos_free_all();
   circuitmux_ewma_free_all();
+  accounting_free_all();
+
   if (!postfork) {
     config_free_all();
     or_state_free_all();





More information about the tor-commits mailing list