[tor-commits] [tor/master] Multithreading support for event-queue code.

nickm at torproject.org nickm at torproject.org
Tue Aug 18 13:10:55 UTC 2015


commit e2a6a7ec6178834c3de7a3be614679120e2c00c8
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed Aug 12 10:10:11 2015 -0400

    Multithreading support for event-queue code.
---
 src/or/control.c |   61 ++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 46 insertions(+), 15 deletions(-)

diff --git a/src/or/control.c b/src/or/control.c
index 4b8e9c1..2be99d5 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -594,13 +594,20 @@ typedef struct queued_event_s {
   char *msg;
 } queued_event_t;
 
-/** If this is greater than 0, we don't allow new events to be queued. */
+/** If this is greater than 0, we don't allow new events to be queued.
+ * XXXX This should be thread-local. */
 static int block_event_queue = 0;
 
 /** Holds a smartlist of queued_event_t objects that may need to be sent
  * to one or more controllers */
 static smartlist_t *queued_control_events = NULL;
 
+/** True if the flush_queued_events_event is pending. */
+static int flush_queued_event_pending = 0;
+
+/** Lock to protect the above fields. */
+static tor_mutex_t *queued_control_events_lock = NULL;
+
 /** An event that should fire in order to flush the contents of
  * queued_control_events. */
 static struct event *flush_queued_events_event = NULL;
@@ -621,6 +628,10 @@ control_initialize_event_queue(void)
       tor_assert(flush_queued_events_event);
     }
   }
+
+  if (queued_control_events_lock == NULL) {
+    queued_control_events_lock = tor_mutex_new();
+  }
 }
 
 /** Helper: inserts an event on the list of events queued to be sent to
@@ -643,30 +654,43 @@ queue_control_event_string,(uint16_t event, char *msg))
     tor_free(msg);
     return;
   }
-  if (block_event_queue) {
-    tor_free(msg);
-    return;
-  }
 
   queued_event_t *ev = tor_malloc(sizeof(*ev));
   ev->event = event;
   ev->msg = msg;
 
+  tor_mutex_acquire(queued_control_events_lock);
+  if (block_event_queue) { /* XXXX This should be thread-specific. */
+    tor_mutex_release(queued_control_events_lock);
+    tor_free(msg);
+    tor_free(ev);
+    return;
+  }
+
   /* No queueing an event while queueing an event */
   ++block_event_queue;
 
   tor_assert(queued_control_events);
   smartlist_add(queued_control_events, ev);
 
-  /* We just put the first event on the queue; mark the queue to be
-   * flushed.
+  int activate_event = 0;
+  if (! flush_queued_event_pending && in_main_thread()) {
+    activate_event = 1;
+    flush_queued_event_pending = 1;
+  }
+
+  --block_event_queue;
+
+  tor_mutex_release(queued_control_events_lock);
+
+  /* We just put an event on the queue; mark the queue to be
+   * flushed.  We only do this from the main thread for now; otherwise,
+   * we'd need to incur locking overhead in Libevent or use a socket.
    */
-  if (smartlist_len(queued_control_events) == 1) {
+  if (activate_event) {
     tor_assert(flush_queued_events_event);
     event_active(flush_queued_events_event, EV_READ, 1);
   }
-
-  --block_event_queue;
 }
 
 /** Release all storage held by <b>ev</b>. */
@@ -687,15 +711,20 @@ queued_event_free(queued_event_t *ev)
 static void
 queued_events_flush_all(int force)
 {
-  smartlist_t *all_conns = get_connection_array();
-  smartlist_t *controllers = smartlist_new();
-
   if (PREDICT_UNLIKELY(queued_control_events == NULL)) {
     return;
   }
+  smartlist_t *all_conns = get_connection_array();
+  smartlist_t *controllers = smartlist_new();
+  smartlist_t *queued_events;
 
+  tor_mutex_acquire(queued_control_events_lock);
   /* No queueing an event while flushing events. */
   ++block_event_queue;
+  flush_queued_event_pending = 0;
+  queued_events = queued_control_events;
+  queued_control_events = smartlist_new();
+  tor_mutex_release(queued_control_events_lock);
 
   /* Gather all the controllers that will care... */
   SMARTLIST_FOREACH_BEGIN(all_conns, connection_t *, conn) {
@@ -708,7 +737,7 @@ queued_events_flush_all(int force)
     }
   } SMARTLIST_FOREACH_END(conn);
 
-  SMARTLIST_FOREACH_BEGIN(queued_control_events, queued_event_t *, ev) {
+  SMARTLIST_FOREACH_BEGIN(queued_events, queued_event_t *, ev) {
     const event_mask_t bit = ((event_mask_t)1) << ev->event;
     const size_t msg_len = strlen(ev->msg);
     SMARTLIST_FOREACH_BEGIN(controllers, control_connection_t *,
@@ -728,10 +757,12 @@ queued_events_flush_all(int force)
     } SMARTLIST_FOREACH_END(control_conn);
   }
 
-  smartlist_clear(queued_control_events);
+  smartlist_free(queued_events);
   smartlist_free(controllers);
 
+  tor_mutex_acquire(queued_control_events_lock);
   --block_event_queue;
+  tor_mutex_release(queued_control_events_lock);
 }
 
 /** Libevent callback: Flushes pending events to controllers that are





More information about the tor-commits mailing list