From 28b755e66007c94521c45bdda07abdf3bcd59656 Mon Sep 17 00:00:00 2001 From: Roger Dingledine Date: Mon, 31 Oct 2016 00:20:22 -0400 Subject: [PATCH 1/3] refactor out the tor_event_base_loopexit() call no actual changes --- src/or/main.c | 25 +++++++++++++++++-------- src/or/main.h | 2 ++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/or/main.c b/src/or/main.c index 6b5619c7d..cba19c38b 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -726,6 +726,19 @@ 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 + * finish. */ +void +tell_event_loop_to_finish(void) +{ + if (!called_loop_once) { + struct timeval tv = { 0, 0 }; + tor_event_base_loopexit(tor_libevent_get_base(), &tv); + called_loop_once = 1; /* hack to avoid adding more exit events */ + } +} + /** Helper: Tell the main loop to begin reading bytes into conn from * its linked connection, if it is not doing so already. Called by * connection_start_reading and connection_start_writing as appropriate. */ @@ -738,14 +751,10 @@ 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); - if (!called_loop_once) { - /* This is the first event on the list; we won't be in LOOP_ONCE mode, - * so we need to make sure that the event_base_loop() actually exits at - * the end of its run through the current connections and lets us - * activate read events for linked connections. */ - struct timeval tv = { 0, 0 }; - tor_event_base_loopexit(tor_libevent_get_base(), &tv); - } + /* 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_finish(); } else { tor_assert(smartlist_contains(active_linked_connection_lst, conn)); } diff --git a/src/or/main.h b/src/or/main.h index ad865b812..6949376f3 100644 --- a/src/or/main.h +++ b/src/or/main.h @@ -45,6 +45,8 @@ 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_finish(void); + void connection_stop_reading_from_linked_conn(connection_t *conn); void directory_all_unreachable(time_t now); From d89804a69d1b1f92076d47aac953776e1a3cd867 Mon Sep 17 00:00:00 2001 From: Roger Dingledine Date: Mon, 31 Oct 2016 00:23:53 -0400 Subject: [PATCH 2/3] Ask event_base_loop to finish when we add a pending stream Fixes bug 19969; bugfix on b1d56fc58. We can fix this some more in later Tors, but for now, this is probably the right fix for us. --- changes/bug19969 | 10 ++++++++++ src/or/connection_edge.c | 9 +++++++++ 2 files changed, 19 insertions(+) create mode 100644 changes/bug19969 diff --git a/changes/bug19969 b/changes/bug19969 new file mode 100644 index 000000000..0bdd880bb --- /dev/null +++ b/changes/bug19969 @@ -0,0 +1,10 @@ + o Major bugfixes (client performance); + - Clients now respond to new application stream requests when + they arrive, rather than waiting up to one second before starting + to handle them. Fixes part of bug 19969; bugfix on 0.2.8.1-alpha. + + o Major bugfixes (clients on flaky network connections); + - When Tor leaves standby because of a new application request, open + circuits as needed to serve that request. Previously, we would + potentially wait a very long time. Fixes part of bug 19969; bugfix + on 0.2.8.1-alpha. diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 754e9762e..8098fb017 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -892,6 +892,15 @@ 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_finish(); } /** Mark entry_conn as no longer waiting for a circuit. */ From b2f82d45b7e0166a8de3a7b6d38e288dd1e6d96e Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Mon, 31 Oct 2016 14:42:26 -0400 Subject: [PATCH 3/3] Always call connection_ap_attach_pending() once a second. Fixes bug 19969; bugfix on b1d56fc58. We can fix this some more in later Tors, but for now, this is probably the simplest fix possible. This is a belt-and-suspenders fix, where the earlier fix ("Ask event_base_loop to finish when we add a pending stream") aims to respond to new streams as soon as they arrive, and this one aims to make sure that we definitely respond to all of the streams. --- src/or/main.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/or/main.c b/src/or/main.c index cba19c38b..d4d98ee31 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -1525,6 +1525,12 @@ run_scheduled_events(time_t now) circuit_expire_old_circs_as_needed(now); } + if (!net_is_disabled()) { + /* This is usually redundant with circuit_build_needed_circs() above, + * but it is very fast when there is no work to do. */ + connection_ap_attach_pending(0); + } + /* 5. We do housekeeping for each connection... */ connection_or_set_bad_connections(NULL, 0); int i;