summaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2018-04-13 12:12:46 -0400
committerNick Mathewson <nickm@torproject.org>2018-04-13 12:12:46 -0400
commit61d87dfa1509aaf209ff72d7c5e091d06b191040 (patch)
treec09b01f75bf76c5274cf01341ff6e102eb6d1e23 /src/or
parentb152d62cee7480ee7b9b68dd9b619db65b6cd112 (diff)
parent4c03af48806ac03e5754a7531ee9e915fc2f6c8c (diff)
downloadtor-61d87dfa1509aaf209ff72d7c5e091d06b191040.tar.gz
tor-61d87dfa1509aaf209ff72d7c5e091d06b191040.zip
Merge branch 'postloop_callbacks_2'
Diffstat (limited to 'src/or')
-rw-r--r--src/or/connection_edge.c32
-rw-r--r--src/or/main.c66
-rw-r--r--src/or/main.h1
3 files changed, 51 insertions, 48 deletions
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 948c8722bf..955f942c50 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -611,6 +611,12 @@ static smartlist_t *pending_entry_connections = NULL;
static int untried_pending_connections = 0;
+/**
+ * Mainloop event to tell us to scan for pending connections that can
+ * be attached.
+ */
+static mainloop_event_t *attach_pending_entry_connections_ev = NULL;
+
/** Common code to connection_(ap|exit)_about_to_close. */
static void
connection_edge_about_to_close(edge_connection_t *edge_conn)
@@ -956,6 +962,14 @@ connection_ap_attach_pending(int retry)
untried_pending_connections = 0;
}
+static void
+attach_pending_entry_connections_cb(mainloop_event_t *ev, void *arg)
+{
+ (void)ev;
+ (void)arg;
+ connection_ap_attach_pending(0);
+}
+
/** Mark <b>entry_conn</b> as needing to get attached to a circuit.
*
* And <b>entry_conn</b> must be in AP_CONN_STATE_CIRCUIT_WAIT,
@@ -973,9 +987,13 @@ connection_ap_mark_as_pending_circuit_(entry_connection_t *entry_conn,
if (conn->marked_for_close)
return;
- if (PREDICT_UNLIKELY(NULL == pending_entry_connections))
+ if (PREDICT_UNLIKELY(NULL == pending_entry_connections)) {
pending_entry_connections = smartlist_new();
-
+ }
+ if (PREDICT_UNLIKELY(NULL == attach_pending_entry_connections_ev)) {
+ attach_pending_entry_connections_ev = mainloop_event_postloop_new(
+ attach_pending_entry_connections_cb, NULL);
+ }
if (PREDICT_UNLIKELY(smartlist_contains(pending_entry_connections,
entry_conn))) {
log_warn(LD_BUG, "What?? pending_entry_connections already contains %p! "
@@ -999,14 +1017,7 @@ connection_ap_mark_as_pending_circuit_(entry_connection_t *entry_conn,
untried_pending_connections = 1;
smartlist_add(pending_entry_connections, entry_conn);
- /* Work-around for bug 19969: we handle pending_entry_connections at
- * the end of run_main_loop_once(), but in many cases that function will
- * take a very long time, if ever, to finish its call to event_base_loop().
- *
- * So the fix is to tell it right now that it ought to finish its loop at
- * its next available opportunity.
- */
- tell_event_loop_to_run_external_code();
+ mainloop_event_activate(attach_pending_entry_connections_ev);
}
/** Mark <b>entry_conn</b> as no longer waiting for a circuit. */
@@ -4165,5 +4176,6 @@ connection_edge_free_all(void)
untried_pending_connections = 0;
smartlist_free(pending_entry_connections);
pending_entry_connections = NULL;
+ mainloop_event_free(attach_pending_entry_connections_ev);
}
diff --git a/src/or/main.c b/src/or/main.c
index 0e67ea6f68..30f00ae342 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -410,6 +410,27 @@ connection_unlink(connection_t *conn)
connection_free(conn);
}
+/**
+ * Callback: used to activate read events for all linked connections, so
+ * libevent knows to call their read callbacks. This callback run as a
+ * postloop event, so that the events _it_ activates don't happen until
+ * Libevent has a chance to check for other events.
+ */
+static void
+schedule_active_linked_connections_cb(mainloop_event_t *event, void *arg)
+{
+ (void)event;
+ (void)arg;
+
+ /* All active linked conns should get their read events activated,
+ * so that libevent knows to run their callbacks. */
+ SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn,
+ event_active(conn->read_event, EV_READ, 1));
+}
+
+/** Event that invokes schedule_active_linked_connections_cb. */
+static mainloop_event_t *schedule_active_linked_connections_event = NULL;
+
/** Initialize the global connection list, closeable connection list,
* and active connection list. */
STATIC void
@@ -710,20 +731,6 @@ connection_should_read_from_linked_conn(connection_t *conn)
return 0;
}
-/** If we called event_base_loop() and told it to never stop until it
- * runs out of events, now we've changed our mind: tell it we want it to
- * exit once the current round of callbacks is done, so that we can
- * run external code, and then return to the main loop. */
-void
-tell_event_loop_to_run_external_code(void)
-{
- if (!called_loop_once) {
- struct timeval tv = { 0, 0 };
- tor_libevent_exit_loop_after_delay(tor_libevent_get_base(), &tv);
- called_loop_once = 1; /* hack to avoid adding more exit events */
- }
-}
-
/** Event to run 'shutdown did not work callback'. */
static struct event *shutdown_did_not_work_event = NULL;
@@ -803,10 +810,7 @@ connection_start_reading_from_linked_conn(connection_t *conn)
if (!conn->active_on_link) {
conn->active_on_link = 1;
smartlist_add(active_linked_connection_lst, conn);
- /* make sure that the event_base_loop() function exits at
- * the end of its run through the current connections, so we can
- * activate read events for linked connections. */
- tell_event_loop_to_run_external_code();
+ mainloop_event_activate(schedule_active_linked_connections_event);
} else {
tor_assert(smartlist_contains(active_linked_connection_lst, conn));
}
@@ -2583,6 +2587,11 @@ do_main_loop(void)
initialize_periodic_events();
}
+ if (!schedule_active_linked_connections_event) {
+ schedule_active_linked_connections_event =
+ mainloop_event_postloop_new(schedule_active_linked_connections_cb, NULL);
+ }
+
/* initialize dns resolve map, spawn workers if needed */
if (dns_init() < 0) {
if (get_options()->ServerDNSAllowBrokenConfig)
@@ -2787,17 +2796,12 @@ run_main_loop_once(void)
errno = 0;
#endif
- /* All active linked conns should get their read events activated,
- * so that libevent knows to run their callbacks. */
- SMARTLIST_FOREACH(active_linked_connection_lst, connection_t *, conn,
- event_active(conn->read_event, EV_READ, 1));
-
if (get_options()->MainloopStats) {
/* We always enforce that EVLOOP_ONCE is passed to event_base_loop() if we
* are collecting main loop statistics. */
called_loop_once = 1;
} else {
- called_loop_once = smartlist_len(active_linked_connection_lst) ? 1 : 0;
+ called_loop_once = 0;
}
/* Make sure we know (about) what time it is. */
@@ -2853,19 +2857,6 @@ run_main_loop_once(void)
if (main_loop_should_exit)
return 0;
- /* And here is where we put callbacks that happen "every time the event loop
- * runs." They must be very fast, or else the whole Tor process will get
- * slowed down.
- *
- * Note that this gets called once per libevent loop, which will make it
- * happen once per group of events that fire, or once per second. */
-
- /* If there are any pending client connections, try attaching them to
- * circuits (if we can.) This will be pretty fast if nothing new is
- * pending.
- */
- connection_ap_attach_pending(0);
-
return 1;
}
@@ -3500,6 +3491,7 @@ tor_free_all(int postfork)
tor_event_free(shutdown_did_not_work_event);
tor_event_free(initialize_periodic_events_event);
mainloop_event_free(directory_all_unreachable_cb_event);
+ mainloop_event_free(schedule_active_linked_connections_event);
#ifdef HAVE_SYSTEMD_209
periodic_timer_free(systemd_watchdog_timer);
diff --git a/src/or/main.h b/src/or/main.h
index 9ef5b9472f..0143973b26 100644
--- a/src/or/main.h
+++ b/src/or/main.h
@@ -45,7 +45,6 @@ int connection_is_writing(connection_t *conn);
MOCK_DECL(void,connection_stop_writing,(connection_t *conn));
MOCK_DECL(void,connection_start_writing,(connection_t *conn));
-void tell_event_loop_to_run_external_code(void);
void tor_shutdown_event_loop_and_exit(int exitcode);
int tor_event_loop_shutdown_is_pending(void);