| 
					
				 | 
			
			
				@@ -1383,25 +1383,56 @@ n_cells_in_circ_queues(const circuit_t *c) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return n; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/** helper to sort a list of circuit_q by total queue lengths, in descending 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * order. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Return the age of the oldest cell queued on <b>c</b>, in milliseconds. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Return 0 if there are no cells queued on c.  Requires that <b>now</b> be 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * the current time in milliseconds since the epoch, truncated. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * This function will return incorrect results if the oldest cell queued on 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * the circuit is older than 2**32 msec (about 49 days) old. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static uint32_t 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+circuit_max_queued_cell_age(const circuit_t *c, uint32_t now) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  uint32_t age = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (c->n_conn_cells.head) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    age = now - c->n_conn_cells.head->inserted_time; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (! CIRCUIT_IS_ORIGIN(c)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const or_circuit_t *orcirc = TO_OR_CIRCUIT((circuit_t*)c); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (orcirc->p_conn_cells.head) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      uint32_t age2 = now - orcirc->p_conn_cells.head->inserted_time; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (age2 > age) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return age2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return age; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** Temporary variable for circuits_compare_by_oldest_queued_cell_ This is a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * kludge to work around the fact that qsort doesn't provide a way for 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * comparison functions to take an extra argument. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static uint32_t circcomp_now_tmp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** Helper to sort a list of circuit_t by age of oldest cell, in descending 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * order. Requires that circcomp_now_tmp is set correctly. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-circuits_compare_by_queue_len_(const void **a_, const void **b_) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+circuits_compare_by_oldest_queued_cell_(const void **a_, const void **b_) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const circuit_t *a = *a_; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const circuit_t *b = *b_; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  size_t a_n = n_cells_in_circ_queues(a); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  size_t b_n = n_cells_in_circ_queues(b); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  uint32_t age_a = circuit_max_queued_cell_age(a, circcomp_now_tmp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  uint32_t age_b = circuit_max_queued_cell_age(b, circcomp_now_tmp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (a_n < b_n) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (age_a < age_b) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  else if (a_n == b_n) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  else if (age_a == age_b) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#define FRACTION_OF_CIRCS_TO_RETAIN_ON_OOM 0.90 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#define FRACTION_OF_CELLS_TO_RETAIN_ON_OOM 0.90 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** We're out of memory for cells, having allocated <b>current_allocation</b> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * bytes' worth.  Kill the 'worst' circuits until we're under 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1414,13 +1445,14 @@ circuits_handle_oom(size_t current_allocation) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   circuit_t *circ; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   size_t n_cells_removed=0, n_cells_to_remove; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int n_circuits_killed=0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  struct timeval now; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   log_notice(LD_GENERAL, "We're low on memory.  Killing circuits with " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				              "over-long queues. (This behavior is controlled by " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				              "MaxMemInCellQueues.)"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     size_t mem_target = (size_t)(get_options()->MaxMemInCellQueues * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                 FRACTION_OF_CIRCS_TO_RETAIN_ON_OOM); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                 FRACTION_OF_CELLS_TO_RETAIN_ON_OOM); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     size_t mem_to_recover; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (current_allocation <= mem_target) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       return; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1433,9 +1465,13 @@ circuits_handle_oom(size_t current_allocation) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   for (circ = global_circuitlist; circ; circ = circ->next) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     smartlist_add(circlist, circ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Set circcomp_now_tmp so that the sort can work. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_gettimeofday_cached(&now); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  circcomp_now_tmp = (uint32_t)tv_to_msec(&now); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* 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_queue_len_); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  smartlist_sort(circlist, circuits_compare_by_oldest_queued_cell_); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Okay, now the worst circuits are at the front of the list. Let's mark 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * them, and reclaim their storage aggressively. */ 
			 |