aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2018-05-10 09:05:15 -0400
committerNick Mathewson <nickm@torproject.org>2018-05-10 09:05:15 -0400
commitbeca6a585c5cd594333ae07b0ae3326188f9d67c (patch)
tree2f64a2dacc5edcba93f9508b99487ac79ffbac39 /src
parenta4a7939ae1605936c55d4b483d5f01e947f7575c (diff)
parenta1a7ebfb8dbb9b104771e99571b6a60c70ee1dbe (diff)
downloadtor-beca6a585c5cd594333ae07b0ae3326188f9d67c.tar.gz
tor-beca6a585c5cd594333ae07b0ae3326188f9d67c.zip
Merge branch 'ticket26064'
Diffstat (limited to 'src')
-rw-r--r--src/or/hibernate.c73
-rw-r--r--src/or/hibernate.h1
-rw-r--r--src/or/main.c2
3 files changed, 76 insertions, 0 deletions
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index 98f32adb1c..b83167d20c 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 85fb42864b..4bbda66940 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 e63843b631..69e7f05b14 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -3662,6 +3662,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();