ソースを参照

Merge branch 'bug10116_squashed'

Nick Mathewson 9 年 前
コミット
01a0ab02a3

+ 3 - 0
changes/bug10116

@@ -0,0 +1,3 @@
+  o Minor features:
+    - When handling a low-memory situation, allocate less memory
+      for teporary data structures. Fixes issue 10115.

+ 2 - 2
src/or/circpathbias.c

@@ -1140,11 +1140,10 @@ pathbias_count_circs_in_states(entry_guard_t *guard,
                               path_state_t from,
                               path_state_t to)
 {
-  circuit_t *circ;
   int open_circuits = 0;
 
   /* Count currently open circuits. Give them the benefit of the doubt. */
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     origin_circuit_t *ocirc = NULL;
     if (!CIRCUIT_IS_ORIGIN(circ) || /* didn't originate here */
         circ->marked_for_close) /* already counted */
@@ -1167,6 +1166,7 @@ pathbias_count_circs_in_states(entry_guard_t *guard,
       open_circuits++;
     }
   }
+  SMARTLIST_FOREACH_END(circ);
 
   return open_circuits;
 }

+ 64 - 40
src/or/circuitlist.c

@@ -38,8 +38,7 @@
 /********* START VARIABLES **********/
 
 /** A global list of all circuits at this hop. */
-struct global_circuitlist_s global_circuitlist =
-  TOR_LIST_HEAD_INITIALIZER(global_circuitlist);
+static smartlist_t *global_circuitlist = NULL;
 
 /** A list of all the circuits in CIRCUIT_STATE_CHAN_WAIT. */
 static smartlist_t *circuits_pending_chans = NULL;
@@ -451,17 +450,25 @@ circuit_count_pending_on_channel(channel_t *chan)
 void
 circuit_close_all_marked(void)
 {
-  circuit_t *circ, *tmp;
-  TOR_LIST_FOREACH_SAFE(circ, &global_circuitlist, head, tmp)
-    if (circ->marked_for_close)
+  smartlist_t *lst = circuit_get_global_list();
+  SMARTLIST_FOREACH_BEGIN(lst, circuit_t *, circ) {
+    /* Fix up index if SMARTLIST_DEL_CURRENT just moved this one. */
+    circ->global_circuitlist_idx = circ_sl_idx;
+    if (circ->marked_for_close) {
+      circ->global_circuitlist_idx = -1;
       circuit_free(circ);
+      SMARTLIST_DEL_CURRENT(lst, circ);
+    }
+  } SMARTLIST_FOREACH_END(circ);
 }
 
 /** Return the head of the global linked list of circuits. */
-MOCK_IMPL(struct global_circuitlist_s *,
+MOCK_IMPL(smartlist_t *,
 circuit_get_global_list,(void))
 {
-  return &global_circuitlist;
+  if (NULL == global_circuitlist)
+    global_circuitlist = smartlist_new();
+  return global_circuitlist;
 }
 
 /** Function to make circ-\>state human-readable */
@@ -678,7 +685,8 @@ init_circuit_base(circuit_t *circ)
   circ->deliver_window = CIRCWINDOW_START;
   cell_queue_init(&circ->n_chan_cells);
 
-  TOR_LIST_INSERT_HEAD(&global_circuitlist, circ, head);
+  smartlist_add(circuit_get_global_list(), circ);
+  circ->global_circuitlist_idx = smartlist_len(circuit_get_global_list()) - 1;
 }
 
 /** Allocate space for a new circuit, initializing with <b>p_circ_id</b>
@@ -799,7 +807,16 @@ circuit_free(circuit_t *circ)
   extend_info_free(circ->n_hop);
   tor_free(circ->n_chan_create_cell);
 
-  TOR_LIST_REMOVE(circ, head);
+  if (circ->global_circuitlist_idx != -1) {
+    int idx = circ->global_circuitlist_idx;
+    circuit_t *c2 = smartlist_get(global_circuitlist, idx);
+    tor_assert(c2 == circ);
+    smartlist_del(global_circuitlist, idx);
+    if (idx < smartlist_len(global_circuitlist)) {
+      c2 = smartlist_get(global_circuitlist, idx);
+      c2->global_circuitlist_idx = idx;
+    }
+  }
 
   /* Remove from map. */
   circuit_set_n_circid_chan(circ, 0, NULL);
@@ -841,9 +858,9 @@ circuit_clear_cpath(origin_circuit_t *circ)
 void
 circuit_free_all(void)
 {
-  circuit_t *tmp, *tmp2;
+  smartlist_t *lst = circuit_get_global_list();
 
-  TOR_LIST_FOREACH_SAFE(tmp, &global_circuitlist, head, tmp2) {
+  SMARTLIST_FOREACH_BEGIN(lst, circuit_t *, tmp) {
     if (! CIRCUIT_IS_ORIGIN(tmp)) {
       or_circuit_t *or_circ = TO_OR_CIRCUIT(tmp);
       while (or_circ->resolving_streams) {
@@ -853,8 +870,13 @@ circuit_free_all(void)
         or_circ->resolving_streams = next_conn;
       }
     }
+    tmp->global_circuitlist_idx = -1;
     circuit_free(tmp);
-  }
+    SMARTLIST_DEL_CURRENT(lst, tmp);
+  } SMARTLIST_FOREACH_END(tmp);
+
+  smartlist_free(lst);
+  global_circuitlist = NULL;
 
   smartlist_free(circuits_pending_chans);
   circuits_pending_chans = NULL;
@@ -932,10 +954,9 @@ circuit_dump_conn_details(int severity,
 void
 circuit_dump_by_conn(connection_t *conn, int severity)
 {
-  circuit_t *circ;
   edge_connection_t *tmpconn;
 
-  TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     circid_t n_circ_id = circ->n_circ_id, p_circ_id = 0;
 
     if (circ->marked_for_close) {
@@ -966,6 +987,7 @@ circuit_dump_by_conn(connection_t *conn, int severity)
       }
     }
   }
+  SMARTLIST_FOREACH_END(circ);
 }
 
 /** Return the circuit whose global ID is <b>id</b>, or NULL if no
@@ -973,8 +995,7 @@ circuit_dump_by_conn(connection_t *conn, int severity)
 origin_circuit_t *
 circuit_get_by_global_id(uint32_t id)
 {
-  circuit_t *circ;
-  TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     if (CIRCUIT_IS_ORIGIN(circ) &&
         TO_ORIGIN_CIRCUIT(circ)->global_identifier == id) {
       if (circ->marked_for_close)
@@ -983,6 +1004,7 @@ circuit_get_by_global_id(uint32_t id)
         return TO_ORIGIN_CIRCUIT(circ);
     }
   }
+  SMARTLIST_FOREACH_END(circ);
   return NULL;
 }
 
@@ -1151,17 +1173,17 @@ circuit_unlink_all_from_channel(channel_t *chan, int reason)
 
 #ifdef DEBUG_CIRCUIT_UNLINK_ALL
   {
-    circuit_t *circ;
     smartlist_t *detached_2 = smartlist_new();
     int mismatch = 0, badlen = 0;
 
-    TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+    SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
       if (circ->n_chan == chan ||
           (!CIRCUIT_IS_ORIGIN(circ) &&
            TO_OR_CIRCUIT(circ)->p_chan == chan)) {
         smartlist_add(detached_2, circ);
       }
     }
+    SMARTLIST_FOREACH_END(circ);
 
     if (smartlist_len(detached) != smartlist_len(detached_2)) {
        log_warn(LD_BUG, "List of detached circuits had the wrong length! "
@@ -1235,8 +1257,7 @@ circuit_unlink_all_from_channel(channel_t *chan, int reason)
 origin_circuit_t *
 circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data)
 {
-  circuit_t *circ;
-  TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     if (!circ->marked_for_close &&
         circ->purpose == CIRCUIT_PURPOSE_C_REND_READY) {
       origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
@@ -1249,6 +1270,7 @@ circuit_get_ready_rend_circ_by_rend_data(const rend_data_t *rend_data)
         return ocirc;
     }
   }
+  SMARTLIST_FOREACH_END(circ);
   return NULL;
 }
 
@@ -1261,14 +1283,17 @@ origin_circuit_t *
 circuit_get_next_by_pk_and_purpose(origin_circuit_t *start,
                                    const char *digest, uint8_t purpose)
 {
-  circuit_t *circ;
+  int idx;
+  smartlist_t *lst = circuit_get_global_list();
   tor_assert(CIRCUIT_PURPOSE_IS_ORIGIN(purpose));
   if (start == NULL)
-    circ = TOR_LIST_FIRST(&global_circuitlist);
+    idx = 0;
   else
-    circ = TOR_LIST_NEXT(TO_CIRCUIT(start), head);
+    idx = TO_CIRCUIT(start)->global_circuitlist_idx + 1;
+
+  for ( ; idx < smartlist_len(lst); ++idx) {
+    circuit_t *circ = smartlist_get(lst, idx);
 
-  for ( ; circ; circ = TOR_LIST_NEXT(circ, head)) {
     if (circ->marked_for_close)
       continue;
     if (circ->purpose != purpose)
@@ -1469,7 +1494,6 @@ origin_circuit_t *
 circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
                             int flags)
 {
-  circuit_t *circ_;
   origin_circuit_t *best=NULL;
   int need_uptime = (flags & CIRCLAUNCH_NEED_UPTIME) != 0;
   int need_capacity = (flags & CIRCLAUNCH_NEED_CAPACITY) != 0;
@@ -1485,7 +1509,7 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
             "capacity %d, internal %d",
             purpose, need_uptime, need_capacity, internal);
 
-  TOR_LIST_FOREACH(circ_, &global_circuitlist, head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ_) {
     if (CIRCUIT_IS_ORIGIN(circ_) &&
         circ_->state == CIRCUIT_STATE_OPEN &&
         !circ_->marked_for_close &&
@@ -1535,6 +1559,7 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
       }
     }
   }
+  SMARTLIST_FOREACH_END(circ_);
   return best;
 }
 
@@ -1574,13 +1599,13 @@ circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum)
 void
 circuit_mark_all_unused_circs(void)
 {
-  circuit_t *circ;
-  TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     if (CIRCUIT_IS_ORIGIN(circ) &&
         !circ->marked_for_close &&
         !circ->timestamp_dirty)
       circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
   }
+  SMARTLIST_FOREACH_END(circ);
 }
 
 /** Go through the circuitlist; for each circuit that starts at us
@@ -1593,14 +1618,14 @@ circuit_mark_all_unused_circs(void)
 void
 circuit_mark_all_dirty_circs_as_unusable(void)
 {
-  circuit_t *circ;
-  TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     if (CIRCUIT_IS_ORIGIN(circ) &&
         !circ->marked_for_close &&
         circ->timestamp_dirty) {
       mark_circuit_unusable_for_new_conns(TO_ORIGIN_CIRCUIT(circ));
     }
   }
+  SMARTLIST_FOREACH_END(circ);
 }
 
 /** Mark <b>circ</b> to be closed next time we call
@@ -1950,9 +1975,7 @@ circuits_compare_by_oldest_queued_item_(const void **a_, const void **b_)
 void
 circuits_handle_oom(size_t current_allocation)
 {
-  /* Let's hope there's enough slack space for this allocation here... */
-  smartlist_t *circlist = smartlist_new();
-  circuit_t *circ;
+  smartlist_t *circlist;
   size_t mem_to_recover;
   size_t mem_recovered=0;
   int n_circuits_killed=0;
@@ -1984,17 +2007,20 @@ circuits_handle_oom(size_t current_allocation)
   tor_gettimeofday_cached_monotonic(&now);
   now_ms = (uint32_t)tv_to_msec(&now);
 
-  /* This algorithm itself assumes that you've got enough memory slack
-   * to actually run it. */
-  TOR_LIST_FOREACH(circ, &global_circuitlist, head) {
+  circlist = circuit_get_global_list();
+  SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) {
     circ->age_tmp = circuit_max_queued_item_age(circ, now_ms);
-    smartlist_add(circlist, circ);
-  }
+  } SMARTLIST_FOREACH_END(circ);
 
   /* This is O(n log n); there are faster algorithms we could use instead.
    * Let's hope this doesn't happen enough to be in the critical path. */
   smartlist_sort(circlist, circuits_compare_by_oldest_queued_item_);
 
+  /* Fix up the indices before we run into trouble */
+  SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) {
+    circ->global_circuitlist_idx = circ_sl_idx;
+  } SMARTLIST_FOREACH_END(circ);
+
   /* Okay, now the worst circuits are at the front of the list. Let's mark
    * them, and reclaim their storage aggressively. */
   SMARTLIST_FOREACH_BEGIN(circlist, circuit_t *, circ) {
@@ -2026,8 +2052,6 @@ circuits_handle_oom(size_t current_allocation)
              U64_PRINTF_ARG(mem_recovered),
              n_circuits_killed,
              smartlist_len(circlist) - n_circuits_killed);
-
-  smartlist_free(circlist);
 }
 
 /** Verify that cpath layer <b>cp</b> has all of its invariants

+ 1 - 3
src/or/circuitlist.h

@@ -14,9 +14,7 @@
 
 #include "testsupport.h"
 
-TOR_LIST_HEAD(global_circuitlist_s, circuit_t);
-
-MOCK_DECL(struct global_circuitlist_s*, circuit_get_global_list, (void));
+MOCK_DECL(smartlist_t *, circuit_get_global_list, (void));
 const char *circuit_state_to_string(int state);
 const char *circuit_purpose_to_controller_string(uint8_t purpose);
 const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose);

+ 21 - 25
src/or/circuituse.c

@@ -268,7 +268,6 @@ circuit_get_best(const entry_connection_t *conn,
                  int must_be_open, uint8_t purpose,
                  int need_uptime, int need_internal)
 {
-  circuit_t *circ;
   origin_circuit_t *best=NULL;
   struct timeval now;
   int intro_going_on_but_too_old = 0;
@@ -281,7 +280,7 @@ circuit_get_best(const entry_connection_t *conn,
 
   tor_gettimeofday(&now);
 
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     origin_circuit_t *origin_circ;
     if (!CIRCUIT_IS_ORIGIN(circ))
       continue;
@@ -305,6 +304,7 @@ circuit_get_best(const entry_connection_t *conn,
     if (!best || circuit_is_better(origin_circ,best,conn))
       best = origin_circ;
   }
+  SMARTLIST_FOREACH_END(circ);
 
   if (!best && intro_going_on_but_too_old)
     log_info(LD_REND|LD_CIRC, "There is an intro circuit being created "
@@ -318,11 +318,9 @@ circuit_get_best(const entry_connection_t *conn,
 static int
 count_pending_general_client_circuits(void)
 {
-  const circuit_t *circ;
-
   int count = 0;
 
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     if (circ->marked_for_close ||
         circ->state == CIRCUIT_STATE_OPEN ||
         circ->purpose != CIRCUIT_PURPOSE_C_GENERAL ||
@@ -331,6 +329,7 @@ count_pending_general_client_circuits(void)
 
     ++count;
   }
+  SMARTLIST_FOREACH_END(circ);
 
   return count;
 }
@@ -370,7 +369,6 @@ circuit_conforms_to_options(const origin_circuit_t *circ,
 void
 circuit_expire_building(void)
 {
-  circuit_t *victim, *next_circ;
   /* circ_times.timeout_ms and circ_times.close_ms are from
    * circuit_build_times_get_initial_timeout() if we haven't computed
    * custom timeouts yet */
@@ -388,7 +386,7 @@ circuit_expire_building(void)
    * we want to be more lenient with timeouts, in case the
    * user has relocated and/or changed network connections.
    * See bug #3443. */
-  TOR_LIST_FOREACH(next_circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, next_circ) {
     if (!CIRCUIT_IS_ORIGIN(next_circ) || /* didn't originate here */
         next_circ->marked_for_close) { /* don't mess with marked circs */
       continue;
@@ -402,7 +400,7 @@ circuit_expire_building(void)
       any_opened_circs = 1;
       break;
     }
-  }
+  } SMARTLIST_FOREACH_END(next_circ);
 
 #define SET_CUTOFF(target, msec) do {                       \
     long ms = tor_lround(msec);                             \
@@ -473,9 +471,8 @@ circuit_expire_building(void)
              MAX(get_circuit_build_close_time_ms()*2 + 1000,
                  options->SocksTimeout * 1000));
 
-  TOR_LIST_FOREACH(next_circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *,victim) {
     struct timeval cutoff;
-    victim = next_circ;
     if (!CIRCUIT_IS_ORIGIN(victim) || /* didn't originate here */
         victim->marked_for_close)     /* don't mess with marked circs */
       continue;
@@ -780,7 +777,7 @@ circuit_expire_building(void)
       circuit_mark_for_close(victim, END_CIRC_REASON_TIMEOUT);
 
     pathbias_count_timeout(TO_ORIGIN_CIRCUIT(victim));
-  }
+  } SMARTLIST_FOREACH_END(victim);
 }
 
 /** For debugging #8387: track when we last called
@@ -800,9 +797,8 @@ circuit_log_ancient_one_hop_circuits(int age)
   time_t cutoff = now - age;
   int n_found = 0;
   smartlist_t *log_these = smartlist_new();
-  const circuit_t *circ;
 
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     const origin_circuit_t *ocirc;
     if (! CIRCUIT_IS_ORIGIN(circ))
       continue;
@@ -817,6 +813,7 @@ circuit_log_ancient_one_hop_circuits(int age)
         smartlist_add(log_these, (origin_circuit_t*) ocirc);
     }
   }
+  SMARTLIST_FOREACH_END(circ);
 
   if (n_found == 0)
     goto done;
@@ -831,7 +828,7 @@ circuit_log_ancient_one_hop_circuits(int age)
     int stream_num;
     const edge_connection_t *conn;
     char *dirty = NULL;
-    circ = TO_CIRCUIT(ocirc);
+    const circuit_t *circ = TO_CIRCUIT(ocirc);
 
     format_local_iso_time(created,
                           (time_t)circ->timestamp_created.tv_sec);
@@ -938,7 +935,6 @@ int
 circuit_stream_is_being_handled(entry_connection_t *conn,
                                 uint16_t port, int min)
 {
-  circuit_t *circ;
   const node_t *exitnode;
   int num=0;
   time_t now = time(NULL);
@@ -946,7 +942,7 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
                                    get_options()->LongLivedPorts,
                                    conn ? conn->socks_request->port : port);
 
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     if (CIRCUIT_IS_ORIGIN(circ) &&
         !circ->marked_for_close &&
         circ->purpose == CIRCUIT_PURPOSE_C_GENERAL &&
@@ -976,6 +972,7 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
       }
     }
   }
+  SMARTLIST_FOREACH_END(circ);
   return 0;
 }
 
@@ -989,7 +986,6 @@ circuit_stream_is_being_handled(entry_connection_t *conn,
 static void
 circuit_predict_and_launch_new(void)
 {
-  circuit_t *circ;
   int num=0, num_internal=0, num_uptime_internal=0;
   int hidserv_needs_uptime=0, hidserv_needs_capacity=1;
   int port_needs_uptime=0, port_needs_capacity=1;
@@ -997,7 +993,7 @@ circuit_predict_and_launch_new(void)
   int flags = 0;
 
   /* First, count how many of each type of circuit we have already. */
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     cpath_build_state_t *build_state;
     origin_circuit_t *origin_circ;
     if (!CIRCUIT_IS_ORIGIN(circ))
@@ -1020,6 +1016,7 @@ circuit_predict_and_launch_new(void)
     if (build_state->need_uptime && build_state->is_internal)
       num_uptime_internal++;
   }
+  SMARTLIST_FOREACH_END(circ);
 
   /* If that's enough, then stop now. */
   if (num >= MAX_UNUSED_OPEN_CIRCUITS)
@@ -1223,7 +1220,6 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
 static void
 circuit_expire_old_circuits_clientside(void)
 {
-  circuit_t *circ;
   struct timeval cutoff, now;
 
   tor_gettimeofday(&now);
@@ -1239,7 +1235,7 @@ circuit_expire_old_circuits_clientside(void)
     cutoff.tv_sec -= get_options()->CircuitIdleTimeout;
   }
 
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     if (circ->marked_for_close || !CIRCUIT_IS_ORIGIN(circ))
       continue;
     /* If the circuit has been dirty for too long, and there are no streams
@@ -1291,7 +1287,7 @@ circuit_expire_old_circuits_clientside(void)
         }
       }
     }
-  }
+  } SMARTLIST_FOREACH_END(circ);
 }
 
 /** How long do we wait before killing circuits with the properties
@@ -1318,11 +1314,10 @@ circuit_expire_old_circuits_clientside(void)
 void
 circuit_expire_old_circuits_serverside(time_t now)
 {
-  circuit_t *circ;
   or_circuit_t *or_circ;
   time_t cutoff = now - IDLE_ONE_HOP_CIRC_TIMEOUT;
 
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     if (circ->marked_for_close || CIRCUIT_IS_ORIGIN(circ))
       continue;
     or_circ = TO_OR_CIRCUIT(circ);
@@ -1339,6 +1334,7 @@ circuit_expire_old_circuits_serverside(time_t now)
       circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED);
     }
   }
+  SMARTLIST_FOREACH_END(circ);
 }
 
 /** Number of testing circuits we want open before testing our bandwidth. */
@@ -1363,18 +1359,18 @@ reset_bandwidth_test(void)
 int
 circuit_enough_testing_circs(void)
 {
-  circuit_t *circ;
   int num = 0;
 
   if (have_performed_bandwidth_test)
     return 1;
 
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     if (!circ->marked_for_close && CIRCUIT_IS_ORIGIN(circ) &&
         circ->purpose == CIRCUIT_PURPOSE_TESTING &&
         circ->state == CIRCUIT_STATE_OPEN)
       num++;
   }
+  SMARTLIST_FOREACH_END(circ);
   return num >= NUM_PARALLEL_TESTING_CIRCS;
 }
 

+ 8 - 8
src/or/control.c

@@ -194,14 +194,14 @@ log_severity_to_event(int severity)
 static void
 clear_circ_bw_fields(void)
 {
-  circuit_t *circ;
   origin_circuit_t *ocirc;
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     if (!CIRCUIT_IS_ORIGIN(circ))
       continue;
     ocirc = TO_ORIGIN_CIRCUIT(circ);
     ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0;
   }
+  SMARTLIST_FOREACH_END(circ);
 }
 
 /** Set <b>global_event_mask*</b> to the bitwise OR of each live control
@@ -1879,9 +1879,8 @@ getinfo_helper_events(control_connection_t *control_conn,
 {
   (void) control_conn;
   if (!strcmp(question, "circuit-status")) {
-    circuit_t *circ_;
     smartlist_t *status = smartlist_new();
-    TOR_LIST_FOREACH(circ_, circuit_get_global_list(), head) {
+    SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ_) {
       origin_circuit_t *circ;
       char *circdesc;
       const char *state;
@@ -1903,6 +1902,7 @@ getinfo_helper_events(control_connection_t *control_conn,
                    state, *circdesc ? " " : "", circdesc);
       tor_free(circdesc);
     }
+    SMARTLIST_FOREACH_END(circ_);
     *answer = smartlist_join_strings(status, "\r\n", 0, NULL);
     SMARTLIST_FOREACH(status, char *, cp, tor_free(cp));
     smartlist_free(status);
@@ -3908,12 +3908,11 @@ control_event_stream_bandwidth_used(void)
 int
 control_event_circ_bandwidth_used(void)
 {
-  circuit_t *circ;
   origin_circuit_t *ocirc;
   if (!EVENT_IS_INTERESTING(EVENT_CIRC_BANDWIDTH_USED))
     return 0;
 
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     if (!CIRCUIT_IS_ORIGIN(circ))
       continue;
     ocirc = TO_ORIGIN_CIRCUIT(circ);
@@ -3926,6 +3925,7 @@ control_event_circ_bandwidth_used(void)
                        (unsigned long)ocirc->n_written_circ_bw);
     ocirc->n_written_circ_bw = ocirc->n_read_circ_bw = 0;
   }
+  SMARTLIST_FOREACH_END(circ);
 
   return 0;
 }
@@ -4090,14 +4090,13 @@ format_cell_stats(char **event_string, circuit_t *circ,
 int
 control_event_circuit_cell_stats(void)
 {
-  circuit_t *circ;
   cell_stats_t *cell_stats;
   char *event_string;
   if (!get_options()->TestingEnableCellStatsEvent ||
       !EVENT_IS_INTERESTING(EVENT_CELL_STATS))
     return 0;
   cell_stats = tor_malloc(sizeof(cell_stats_t));;
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     if (!circ->testing_cell_stats)
       continue;
     sum_up_cell_stats_by_command(circ, cell_stats);
@@ -4106,6 +4105,7 @@ control_event_circuit_cell_stats(void)
                        "650 CELL_STATS %s\r\n", event_string);
     tor_free(event_string);
   }
+  SMARTLIST_FOREACH_END(circ);
   tor_free(cell_stats);
   return 0;
 }

+ 2 - 2
src/or/or.h

@@ -2864,8 +2864,8 @@ typedef struct circuit_t {
   /** Unique ID for measuring tunneled network status requests. */
   uint64_t dirreq_id;
 
-  /** Next circuit in linked list of all circuits (global_circuitlist). */
-  TOR_LIST_ENTRY(circuit_t) head;
+  /** Index in smartlist of all circuits (global_circuitlist). */
+  int global_circuitlist_idx;
 
   /** Next circuit in the doubly-linked ring of circuits waiting to add
    * cells to n_conn.  NULL if we have no cells pending, or if we're not

+ 2 - 2
src/or/relay.c

@@ -2328,15 +2328,15 @@ packed_cell_free(packed_cell_t *cell)
 void
 dump_cell_pool_usage(int severity)
 {
-  circuit_t *c;
   int n_circs = 0;
   int n_cells = 0;
-  TOR_LIST_FOREACH(c, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, c) {
     n_cells += c->n_chan_cells.n;
     if (!CIRCUIT_IS_ORIGIN(c))
       n_cells += TO_OR_CIRCUIT(c)->p_chan_cells.n;
     ++n_circs;
   }
+  SMARTLIST_FOREACH_END(c);
   tor_log(severity, LD_MM,
           "%d cells allocated on %d circuits. %d cells leaked.",
           n_cells, n_circs, (int)total_cells_allocated - n_cells);

+ 2 - 2
src/or/rendclient.c

@@ -376,9 +376,8 @@ rend_client_rendcirc_has_opened(origin_circuit_t *circ)
 static void
 rend_client_close_other_intros(const char *onion_address)
 {
-  circuit_t *c;
   /* abort parallel intro circs, if any */
-  TOR_LIST_FOREACH(c, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, c) {
     if ((c->purpose == CIRCUIT_PURPOSE_C_INTRODUCING ||
         c->purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) &&
         !c->marked_for_close && CIRCUIT_IS_ORIGIN(c)) {
@@ -393,6 +392,7 @@ rend_client_close_other_intros(const char *onion_address)
       }
     }
   }
+  SMARTLIST_FOREACH_END(c);
 }
 
 /** Called when get an ACK or a NAK for a REND_INTRODUCE1 cell.

+ 4 - 4
src/or/rendservice.c

@@ -524,7 +524,6 @@ rend_config_services(const or_options_t *options, int validate_only)
    * other ones. */
   if (old_service_list && !validate_only) {
     smartlist_t *surviving_services = smartlist_new();
-    circuit_t *circ;
 
     /* Copy introduction points to new services. */
     /* XXXX This is O(n^2), but it's only called on reconfigure, so it's
@@ -544,7 +543,7 @@ rend_config_services(const or_options_t *options, int validate_only)
     /* XXXX it would be nicer if we had a nicer abstraction to use here,
      * so we could just iterate over the list of services to close, but
      * once again, this isn't critical-path code. */
-    TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+    SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
       if (!circ->marked_for_close &&
           circ->state == CIRCUIT_STATE_OPEN &&
           (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
@@ -569,6 +568,7 @@ rend_config_services(const or_options_t *options, int validate_only)
         /* XXXX Is there another reason we should use here? */
       }
     }
+    SMARTLIST_FOREACH_END(circ);
     smartlist_free(surviving_services);
     SMARTLIST_FOREACH(old_service_list, rend_service_t *, ptr,
                       rend_service_free(ptr));
@@ -2384,8 +2384,7 @@ static int
 count_established_intro_points(const char *query)
 {
   int num_ipos = 0;
-  circuit_t *circ;
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     if (!circ->marked_for_close &&
         circ->state == CIRCUIT_STATE_OPEN &&
         (circ->purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO ||
@@ -2396,6 +2395,7 @@ count_established_intro_points(const char *query)
         num_ipos++;
     }
   }
+  SMARTLIST_FOREACH_END(circ);
   return num_ipos;
 }
 

+ 2 - 2
src/or/rephist.c

@@ -2471,7 +2471,6 @@ rep_hist_format_buffer_stats(time_t now)
 time_t
 rep_hist_buffer_stats_write(time_t now)
 {
-  circuit_t *circ;
   char *str = NULL;
 
   if (!start_of_buffer_stats_interval)
@@ -2480,9 +2479,10 @@ rep_hist_buffer_stats_write(time_t now)
     goto done; /* Not ready to write */
 
   /* Add open circuits to the history. */
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head) {
+  SMARTLIST_FOREACH_BEGIN(circuit_get_global_list(), circuit_t *, circ) {
     rep_hist_buffer_stats_add_circ(circ, now);
   }
+  SMARTLIST_FOREACH_END(circ);
 
   /* Generate history string. */
   str = rep_hist_format_buffer_stats(now);

+ 1 - 7
src/or/status.c

@@ -28,13 +28,7 @@ static void log_accounting(const time_t now, const or_options_t *options);
 STATIC int
 count_circuits(void)
 {
-  circuit_t *circ;
-  int nr=0;
-
-  TOR_LIST_FOREACH(circ, circuit_get_global_list(), head)
-    nr++;
-
-  return nr;
+  return smartlist_len(circuit_get_global_list());
 }
 
 /** Take seconds <b>secs</b> and return a newly allocated human-readable

+ 13 - 15
src/test/test_status.c

@@ -30,27 +30,24 @@
  * global circuits.
  */
 
-struct global_circuitlist_s mock_global_circuitlist =
-  TOR_LIST_HEAD_INITIALIZER(global_circuitlist);
+static smartlist_t * mock_global_circuitlist = NULL;
 
-NS_DECL(struct global_circuitlist_s *, circuit_get_global_list, (void));
+NS_DECL(smartlist_t *, circuit_get_global_list, (void));
 
 static void
 NS(test_main)(void *arg)
 {
   /* Choose origin_circuit_t wlog. */
   origin_circuit_t *mock_circuit1, *mock_circuit2;
-  circuit_t *circ, *tmp;
   int expected_circuits = 2, actual_circuits;
 
   (void)arg;
 
   mock_circuit1 = tor_malloc_zero(sizeof(origin_circuit_t));
   mock_circuit2 = tor_malloc_zero(sizeof(origin_circuit_t));
-  TOR_LIST_INSERT_HEAD(
-    &mock_global_circuitlist, TO_CIRCUIT(mock_circuit1), head);
-  TOR_LIST_INSERT_HEAD(
-    &mock_global_circuitlist, TO_CIRCUIT(mock_circuit2), head);
+  mock_global_circuitlist = smartlist_new();
+  smartlist_add(mock_global_circuitlist, TO_CIRCUIT(mock_circuit1));
+  smartlist_add(mock_global_circuitlist, TO_CIRCUIT(mock_circuit2));
 
   NS_MOCK(circuit_get_global_list);
 
@@ -58,17 +55,18 @@ NS(test_main)(void *arg)
 
   tt_assert(expected_circuits == actual_circuits);
 
-  done:
-    TOR_LIST_FOREACH_SAFE(
-        circ, NS(circuit_get_global_list)(), head, tmp);
-      tor_free(circ);
-    NS_UNMOCK(circuit_get_global_list);
+ done:
+  tor_free(mock_circuit1);
+  tor_free(mock_circuit2);
+  smartlist_free(mock_global_circuitlist);
+  mock_global_circuitlist = NULL;
+  NS_UNMOCK(circuit_get_global_list);
 }
 
-static struct global_circuitlist_s *
+static smartlist_t *
 NS(circuit_get_global_list)(void)
 {
-  return &mock_global_circuitlist;
+  return mock_global_circuitlist;
 }
 
 #undef NS_SUBMODULE