commit 1eede00a4bd9a7de2acf77393f2fc57aa3196d08 Merge: beca6a585 8b4cf7771 Author: Nick Mathewson nickm@torproject.org Date: Thu May 10 09:13:28 2018 -0400
Merge branch 'ticket26063_squashed'
changes/ticket26063 | 5 +++ src/common/compat_libevent.c | 31 ++++++++++++++- src/common/compat_libevent.h | 2 + src/or/config.c | 9 +++-- src/or/connection.c | 12 +++--- src/or/connection_edge.c | 1 + src/or/control.c | 89 ++++++++++++++++++++++++++++++++++++++++++-- src/or/control.h | 3 ++ src/or/dirserv.c | 2 +- src/or/hibernate.c | 17 ++++++++- src/or/hibernate.h | 1 + src/or/main.c | 67 +++++++++++++++++---------------- src/or/main.h | 1 + src/or/router.c | 18 +++++++-- src/or/router.h | 1 + 15 files changed, 208 insertions(+), 51 deletions(-)
diff --cc src/or/hibernate.c index b83167d20,24479cff9..d7d259470 --- a/src/or/hibernate.c +++ b/src/or/hibernate.c @@@ -1187,18 -1137,10 +1200,20 @@@ on_hibernate_state_change(hibernate_sta if (prev_state != HIBERNATE_STATE_INITIAL) { rescan_periodic_events(get_options()); } + + reschedule_per_second_timer(); }
+/** 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 --cc src/or/main.c index 69e7f05b1,0493596aa..6cb9b6249 --- a/src/or/main.c +++ b/src/or/main.c @@@ -2495,70 -2491,40 +2491,100 @@@ hs_service_callback(time_t now, const o
/** Timer: used to invoke second_elapsed_callback() once per second. */ static periodic_timer_t *second_timer = NULL; + + /** + * Enable or disable the per-second timer as appropriate, creating it if + * necessary. + */ + void + reschedule_per_second_timer(void) + { + struct timeval one_second; + one_second.tv_sec = 1; + one_second.tv_usec = 0; + + if (! second_timer) { + second_timer = periodic_timer_new(tor_libevent_get_base(), + &one_second, + second_elapsed_callback, + NULL); + tor_assert(second_timer); + } + + const bool run_per_second_events = + control_any_per_second_event_enabled() || ! net_is_completely_disabled(); + + if (run_per_second_events) { + periodic_timer_launch(second_timer, &one_second); + } else { + periodic_timer_disable(second_timer); + } + } + -/** Number of libevent errors in the last second: we die if we get too many. */ -static int n_libevent_errors = 0; -/** Last time that second_elapsed_callback was called. */ +/** Last time that update_current_time was called. */ static time_t current_second = 0; +/** Last time that update_current_time updated current_second. */ +static monotime_coarse_t current_second_last_changed; + +/** + * Set the current time to "now", which should be the value returned by + * time(). Check for clock jumps and track the total number of seconds we + * have been running. + */ +void +update_current_time(time_t now) +{ + if (PREDICT_LIKELY(now == current_second)) { + /* We call this function a lot. Most frequently, the current second + * will not have changed, so we just return. */ + return; + } + + const time_t seconds_elapsed = current_second ? (now - current_second) : 0; + + /* Check the wall clock against the monotonic clock, so we can + * better tell idleness from clock jumps and/or other shenanigans. */ + monotime_coarse_t last_updated; + memcpy(&last_updated, ¤t_second_last_changed, sizeof(last_updated)); + monotime_coarse_get(¤t_second_last_changed); + + /** How much clock jumping do we tolerate? */ +#define NUM_JUMPED_SECONDS_BEFORE_WARN 100 + + /** How much idleness do we tolerate? */ +#define NUM_IDLE_SECONDS_BEFORE_WARN 3600 + + if (seconds_elapsed < -NUM_JUMPED_SECONDS_BEFORE_WARN) { + // moving back in time is always a bad sign. + circuit_note_clock_jumped(seconds_elapsed, false); + } else if (seconds_elapsed >= NUM_JUMPED_SECONDS_BEFORE_WARN) { + /* Compare the monotonic clock to the result of time(). */ + const int32_t monotime_msec_passed = + monotime_coarse_diff_msec32(&last_updated, + ¤t_second_last_changed); + const int monotime_sec_passed = monotime_msec_passed / 1000; + const int discrepancy = monotime_sec_passed - (int)seconds_elapsed; + /* If the monotonic clock deviates from time(NULL), we have a couple of + * possibilities. On some systems, this means we have been suspended or + * sleeping. Everywhere, it can mean that the wall-clock time has + * been changed -- for example, with settimeofday(). + * + * On the other hand, if the monotonic time matches with the wall-clock + * time, we've probably just been idle for a while, with no events firing. + * we tolerate much more of that. + */ + const bool clock_jumped = abs(discrepancy) > 2; + + if (clock_jumped || seconds_elapsed >= NUM_IDLE_SECONDS_BEFORE_WARN) { + circuit_note_clock_jumped(seconds_elapsed, ! clock_jumped); + } + } else if (seconds_elapsed > 0) { + stats_n_seconds_working += seconds_elapsed; + } + + update_approx_time(now); + current_second = now; +}
/** Libevent callback: invoked once every second. */ static void @@@ -2568,33 -2534,34 +2594,21 @@@ second_elapsed_callback(periodic_timer_ * could use Libevent's timers for this rather than checking the current * time against a bunch of timeouts every second. */ time_t now; - size_t bytes_written; - size_t bytes_read; - int seconds_elapsed; (void)timer; (void)arg;
- n_libevent_errors = 0; - - /* log_notice(LD_GENERAL, "Tick."); */ now = time(NULL); - update_approx_time(now);
- /* the second has rolled over. check more stuff. */ - seconds_elapsed = current_second ? (int)(now - current_second) : 0; + /* We don't need to do this once-per-second any more: time-updating is + * only in this callback _because it is a callback_. It should be fine + * to disable this callback, and the time will still get updated. + */ + update_current_time(now);
- /* the second has rolled over. check more stuff. */ - // remove this once it's unneeded - bytes_read = (size_t)(stats_n_bytes_read - stats_prev_n_read); - bytes_written = (size_t)(stats_n_bytes_written - stats_prev_n_written); - stats_prev_n_read = stats_n_bytes_read; - stats_prev_n_written = stats_n_bytes_written; - - control_event_bandwidth_used((uint32_t)bytes_read,(uint32_t)bytes_written); - control_event_stream_bandwidth_used(); - control_event_conn_bandwidth_used(); - control_event_circ_bandwidth_used(); - control_event_circuit_cell_stats(); + /* Maybe some controller events are ready to fire */ + control_per_second_events();
-/** If more than this many seconds have elapsed, probably the clock - * jumped: doesn't count. */ -#define NUM_JUMPED_SECONDS_BEFORE_WARN 100 - if (seconds_elapsed < -NUM_JUMPED_SECONDS_BEFORE_WARN || - seconds_elapsed >= NUM_JUMPED_SECONDS_BEFORE_WARN) { - circuit_note_clock_jumped(seconds_elapsed); - } else if (seconds_elapsed > 0) - stats_n_seconds_working += seconds_elapsed; - run_scheduled_events(now); - - current_second = now; /* remember which second it is, for next time */ }
#ifdef HAVE_SYSTEMD_209